From e763a9c3228e36aa58cdbf0451efbed6484fe4cd Mon Sep 17 00:00:00 2001 From: Olga Matyla Date: Tue, 22 Oct 2024 14:48:34 +0200 Subject: [PATCH 01/11] Django 2.1 --- requirements/base.txt | 4 ++-- src/ralph/admin/tests/tests_functional.py | 1 + src/ralph/admin/widgets.py | 6 +++--- src/ralph/assets/api/filters.py | 4 ++-- src/ralph/assets/api/views.py | 2 +- src/ralph/lib/custom_fields/tests/test_admin.py | 2 +- src/ralph/lib/mixins/fields.py | 8 ++++---- src/ralph/lib/mixins/forms.py | 4 ++-- src/ralph/security/api.py | 2 +- 9 files changed, 17 insertions(+), 16 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index ab77273883..5e2754af8a 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,6 +1,6 @@ -r openstack.txt -r hermes.txt -Django==2.0.13 +Django==2.1.15 Faker==0.9.0 Markdown<3.0 # headerid extension removed in 3.0 - see #3313 for details Pillow==6.2.2 @@ -8,7 +8,7 @@ Unidecode==0.04.18 dj.choices==0.11.0 django-cryptography==0.3 django-extensions==2.2.9 -django-filter==1.0.4 +django-filter==2.0.0 django-import-export==1.2.0 django-money==0.12.3 django-mptt==0.11 diff --git a/src/ralph/admin/tests/tests_functional.py b/src/ralph/admin/tests/tests_functional.py index 5e6959a4dc..053db6e255 100644 --- a/src/ralph/admin/tests/tests_functional.py +++ b/src/ralph/admin/tests/tests_functional.py @@ -254,6 +254,7 @@ def _change_list_factory( model=model, model_admin=model_admin(model, ralph_site), request=request, + sortable_by=[], ) def _get_ordering_list(self, model, model_admin, params, list_display): diff --git a/src/ralph/admin/widgets.py b/src/ralph/admin/widgets.py index 5f5eaf2b35..d906cc12dd 100644 --- a/src/ralph/admin/widgets.py +++ b/src/ralph/admin/widgets.py @@ -42,9 +42,9 @@ def media(self): static(path) for path in js ]) - def render(self, name, value, attrs=None): + def render(self, name, value, attrs=None, renderer=None): attrs['class'] = self.css_class - return super().render(name, value, attrs=attrs) + return super().render(name, value, attrs=attrs, renderer=renderer) class AdminDateWidget(DatepickerWidgetMixin, forms.DateInput): @@ -256,7 +256,7 @@ def render_search_fields_info(self, search_fields): rows.append("- {}\n".format(field)) return ''.join(rows) - def render(self, name, value, attrs=None): + def render(self, name, value, attrs=None, renderer=None): model_options = ( self.rel_to._meta.app_label, self.rel_to._meta.model_name ) diff --git a/src/ralph/assets/api/filters.py b/src/ralph/assets/api/filters.py index 87fd1bf1f7..0c4101a810 100644 --- a/src/ralph/assets/api/filters.py +++ b/src/ralph/assets/api/filters.py @@ -6,9 +6,9 @@ class NetworkableObjectFilters(django_filters.FilterSet): Base filter for all networkable objects for example with IP address. """ configuration_path = django_filters.CharFilter( - name='configuration_path__path' + field_name='configuration_path__path' ) - ip = django_filters.CharFilter(name='ethernet_set__ipaddress__address') + ip = django_filters.CharFilter(field_name='ethernet_set__ipaddress__address') class Meta: fields = [ diff --git a/src/ralph/assets/api/views.py b/src/ralph/assets/api/views.py index a1109c5df7..10514fbce7 100644 --- a/src/ralph/assets/api/views.py +++ b/src/ralph/assets/api/views.py @@ -36,7 +36,7 @@ class EnvironmentViewSet(RalphAPIViewSet): class ServiceFilterSet(django_filters.FilterSet): - active = BooleanFilter(name="active") + active = BooleanFilter(field_name="active") class Meta: model = models.Service diff --git a/src/ralph/lib/custom_fields/tests/test_admin.py b/src/ralph/lib/custom_fields/tests/test_admin.py index d3172f1630..5dc56d4219 100644 --- a/src/ralph/lib/custom_fields/tests/test_admin.py +++ b/src/ralph/lib/custom_fields/tests/test_admin.py @@ -65,7 +65,7 @@ def test_get_customfield_formfield_for_string_field(self): # default_value should be placed self.assertContains( response, - '' + '' ) def test_add_new_custom_field_value_for_existing_object(self): diff --git a/src/ralph/lib/mixins/fields.py b/src/ralph/lib/mixins/fields.py index b78a207e6f..cf0a587631 100644 --- a/src/ralph/lib/mixins/fields.py +++ b/src/ralph/lib/mixins/fields.py @@ -176,8 +176,8 @@ def clean(self, value, model_instance): class TicketIdFieldWidget(AdminTextInputWidget): - def render(self, name, value, attrs=None): - html = super().render(name, value, attrs) + def render(self, name, value, attrs=None, renderer=None): + html = super().render(name, value, attrs, renderer) if value: url = '{}{}'.format(settings.ISSUE_TRACKER_URL, value) final_attrs = {'href': smart_urlquote(url), 'target': '_blank'} @@ -253,7 +253,7 @@ def get_limit_models(self): class TagWidget(forms.TextInput): - def render(self, name, value, attrs=None): + def render(self, name, value, attrs=None, renderer=None): if value is not None and not isinstance(value, six.string_types): value = ', '.join(sorted([ (t if ',' not in t else '"%s"' % t) for t in value @@ -261,7 +261,7 @@ def render(self, name, value, attrs=None): if attrs is None: attrs = {} attrs['class'] = 'vTextField' - return super(TagWidget, self).render(name, value, attrs) + return super(TagWidget, self).render(name, value, attrs, renderer) class TaggitTagField(TagField): diff --git a/src/ralph/lib/mixins/forms.py b/src/ralph/lib/mixins/forms.py index 895d55cdf8..f7184f812e 100644 --- a/src/ralph/lib/mixins/forms.py +++ b/src/ralph/lib/mixins/forms.py @@ -40,13 +40,13 @@ def _get_other_field(self, name, value): name=OTHER_NAME.format(name), value=value.get(OTHER) or '' ) - def render(self, name, value, attrs=None): + def render(self, name, value, attrs=None, renderer=None): show_other = value and value.get('value') == OTHER choice_value = (value.get('value') if value else '') or '' return mark_safe( '
{}{}
'.format( self.css_class, - super().render(name, choice_value, attrs=attrs), + super().render(name, choice_value, attrs=attrs, renderer=renderer), self._get_other_field(name, value) if show_other else '' ) ) diff --git a/src/ralph/security/api.py b/src/ralph/security/api.py index 149ea05c63..0575a7a328 100644 --- a/src/ralph/security/api.py +++ b/src/ralph/security/api.py @@ -89,7 +89,7 @@ def to_internal_value(self, data): class IPFilter(django_filters.FilterSet): ip = django_filters.CharFilter( - name='base_object__ethernet_set__ipaddress__address' + field_name='base_object__ethernet_set__ipaddress__address' ) class Meta: From 1fda29540404b7f4983b40b788a1f703170b30db Mon Sep 17 00:00:00 2001 From: Olga Matyla Date: Tue, 22 Oct 2024 15:20:38 +0200 Subject: [PATCH 02/11] Bump drf --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 5e2754af8a..123a32a4c1 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -18,7 +18,7 @@ django-sitetree==1.13.0 django-taggit-serializer==0.1.7 django-taggit==0.22.2 django-threadlocals==0.8 -djangorestframework==3.7.5 +djangorestframework==3.8.2 djangorestframework_xml==1.2.0 drf-nested-routers==0.11.1 factory-boy==2.11.1 From b0b586333f80b161af8cff2ec754ef1a83ac4e1b Mon Sep 17 00:00:00 2001 From: Olga Matyla Date: Tue, 22 Oct 2024 17:21:58 +0200 Subject: [PATCH 03/11] Fix tests_functional --- src/ralph/admin/tests/tests_functional.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ralph/admin/tests/tests_functional.py b/src/ralph/admin/tests/tests_functional.py index 053db6e255..57f466e9f4 100644 --- a/src/ralph/admin/tests/tests_functional.py +++ b/src/ralph/admin/tests/tests_functional.py @@ -12,6 +12,7 @@ from ralph.admin.views.extra import RalphDetailView, RalphListView from ralph.admin.views.main import RalphChangeList from ralph.tests.admin import CarAdmin, ManufacturerAdmin +from ralph.tests.factories import UserFactory from ralph.tests.mixins import ClientMixin, ReloadUrlsMixin from ralph.tests.models import Car, Foo, TestManufacturer @@ -254,13 +255,14 @@ def _change_list_factory( model=model, model_admin=model_admin(model, ralph_site), request=request, - sortable_by=[], + sortable_by=model_admin.sortable_by, ) def _get_ordering_list(self, model, model_admin, params, list_display): from django.contrib.admin.views.main import ORDER_VAR get_params = '{}={}'.format(ORDER_VAR, '.'.join(map(str, params))) request = RequestFactory().get('/?' + get_params) + request.user = UserFactory() cl = self._change_list_factory( model=Car, model_admin=CarAdmin, From b5efa9f9cd8bc70963e7b516c9598451115d9933 Mon Sep 17 00:00:00 2001 From: Olga Matyla Date: Thu, 7 Nov 2024 15:36:47 +0100 Subject: [PATCH 04/11] Fix custom fields tests --- src/ralph/lib/custom_fields/tests/admin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ralph/lib/custom_fields/tests/admin.py b/src/ralph/lib/custom_fields/tests/admin.py index 475c6622fd..8bb45fbdc4 100644 --- a/src/ralph/lib/custom_fields/tests/admin.py +++ b/src/ralph/lib/custom_fields/tests/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin -from ..admin import CustomFieldValueAdminMixin +from ..admin import CustomFieldAdmin, CustomFieldValueAdminMixin +from ..models import CustomField from .models import ModelA, ModelB, SomeModel site = admin.AdminSite(name="cf_admin") @@ -24,3 +25,4 @@ class ModelBAdmin(CustomFieldValueAdminMixin, admin.ModelAdmin): site.register(SomeModel, SomeModelAdmin) site.register(ModelA, ModelAAdmin) site.register(ModelB, ModelBAdmin) +site.register(CustomField, CustomFieldAdmin) From e700825728b16d4b7f7ef4222a7f85fc4ace364b Mon Sep 17 00:00:00 2001 From: Olga Matyla Date: Fri, 22 Nov 2024 12:33:25 +0100 Subject: [PATCH 05/11] Fix jQuery error in tabularFormset --- src/ralph/admin/templates/admin/includes/javascripts.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ralph/admin/templates/admin/includes/javascripts.html b/src/ralph/admin/templates/admin/includes/javascripts.html index f042f77ba3..64aee38634 100644 --- a/src/ralph/admin/templates/admin/includes/javascripts.html +++ b/src/ralph/admin/templates/admin/includes/javascripts.html @@ -81,9 +81,10 @@ var group_id = $(this).data('group-id'), prefix = $(this).data('prefix'), add_text = $(this).data('add-text'), - delete_text = $(this).data('delete-text'); + delete_text = $(this).data('delete-text'), + selector = "#" + group_id + "-group .tabular.inline-related tbody tr"; (function($) { - $("#" + group_id + "-group .tabular.inline-related tbody tr").tabularFormset({ + $(selector).tabularFormset(selector, { prefix: prefix, addText: add_text, deleteText: delete_text From b45e64ea58feb15cfb6567a5e5c534addb2ec8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Szulc?= Date: Fri, 6 Dec 2024 15:04:51 +0100 Subject: [PATCH 06/11] Django 2.2 --- requirements/base.txt | 10 +++++----- requirements/code_style.txt | 2 +- requirements/prod_ldap.txt | 2 +- src/ralph/admin/templates/admin/includes/favicon.html | 2 +- .../admin/templates/admin/includes/javascripts.html | 2 +- .../dc_view/templates/dc_view/angular_scripts.html | 2 +- src/ralph/lib/transitions/forms.py | 2 +- src/ralph/networks/fields.py | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index 123a32a4c1..2cf5a33e47 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,6 +1,6 @@ -r openstack.txt -r hermes.txt -Django==2.1.15 +Django==2.2.28 Faker==0.9.0 Markdown<3.0 # headerid extension removed in 3.0 - see #3313 for details Pillow==6.2.2 @@ -18,16 +18,16 @@ django-sitetree==1.13.0 django-taggit-serializer==0.1.7 django-taggit==0.22.2 django-threadlocals==0.8 -djangorestframework==3.8.2 -djangorestframework_xml==1.2.0 -drf-nested-routers==0.11.1 +djangorestframework==3.13.1 +djangorestframework_xml==2.0.0 +drf-nested-routers==0.92.5 factory-boy==2.11.1 mysqlclient==1.3.13 netaddr==0.7.18 openpyxl==2.4.0 py-moneyed==1.2 python-dateutil==2.4.2 -pytz==2015.4 +pytz==2024.2 redis==3.2.1 requests-oauthlib==1.3.0 requests==2.20.0 diff --git a/requirements/code_style.txt b/requirements/code_style.txt index 52e99b140f..a261921910 100644 --- a/requirements/code_style.txt +++ b/requirements/code_style.txt @@ -1,3 +1,3 @@ -flake8==3.0.4 +flake8==3.7.9 isort==4.2.5 pyflakes==1.5.0 diff --git a/requirements/prod_ldap.txt b/requirements/prod_ldap.txt index db5ba301a8..99017457f4 100644 --- a/requirements/prod_ldap.txt +++ b/requirements/prod_ldap.txt @@ -1,2 +1,2 @@ -r prod.txt -django-auth-ldap==1.6.1 +django-auth-ldap==2.1.0 diff --git a/src/ralph/admin/templates/admin/includes/favicon.html b/src/ralph/admin/templates/admin/includes/favicon.html index 02a8b36bf1..6731e41738 100644 --- a/src/ralph/admin/templates/admin/includes/favicon.html +++ b/src/ralph/admin/templates/admin/includes/favicon.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} diff --git a/src/ralph/admin/templates/admin/includes/javascripts.html b/src/ralph/admin/templates/admin/includes/javascripts.html index 64aee38634..5bd0aed4e9 100644 --- a/src/ralph/admin/templates/admin/includes/javascripts.html +++ b/src/ralph/admin/templates/admin/includes/javascripts.html @@ -1,4 +1,4 @@ -{% load staticfiles ralph_tags %} +{% load static ralph_tags %} diff --git a/src/ralph/dc_view/templates/dc_view/angular_scripts.html b/src/ralph/dc_view/templates/dc_view/angular_scripts.html index 7815f0841c..262f346471 100644 --- a/src/ralph/dc_view/templates/dc_view/angular_scripts.html +++ b/src/ralph/dc_view/templates/dc_view/angular_scripts.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} diff --git a/src/ralph/lib/transitions/forms.py b/src/ralph/lib/transitions/forms.py index 1440643649..220d811820 100644 --- a/src/ralph/lib/transitions/forms.py +++ b/src/ralph/lib/transitions/forms.py @@ -2,7 +2,7 @@ from django import forms from django.conf import settings from django.utils.html import strip_tags -from django.utils.text import mark_safe +from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from ralph.lib.transitions.models import ( diff --git a/src/ralph/networks/fields.py b/src/ralph/networks/fields.py index 94227fac20..cac8164f58 100644 --- a/src/ralph/networks/fields.py +++ b/src/ralph/networks/fields.py @@ -28,7 +28,7 @@ def db_type(self, connection): max_length=MAX_NETWORK_ADDRESS_LENGTH ).db_type(connection) - def from_db_value(self, value, expression, connection, context): + def from_db_value(self, value, expression, connection, *_, **__): if value is None: return value return ipaddress.ip_network(value) From 8df2e1d40f47dce608239df36994a448ef912b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Szulc?= Date: Fri, 6 Dec 2024 15:27:35 +0100 Subject: [PATCH 07/11] Fix basename Run ruff --- src/ralph/__init__.py | 4 +- src/ralph/__main__.py | 16 +- src/ralph/access_cards/admin.py | 94 +- src/ralph/access_cards/api.py | 33 +- .../access_cards/migrations/0001_initial.py | 102 +- .../migrations/0002_auto_20200116_1248.py | 57 +- .../migrations/0003_auto_20200121_1354.py | 24 +- .../migrations/0004_auto_20200513_1014.py | 25 +- .../migrations/0005_auto_20211022_1038.py | 7 +- .../migrations/0006_auto_20240621_1200.py | 15 +- src/ralph/access_cards/models.py | 159 +-- src/ralph/access_cards/tests/factories.py | 10 +- src/ralph/access_cards/tests/test_api.py | 90 +- src/ralph/accessories/admin.py | 67 +- .../accessories/migrations/0001_initial.py | 156 ++- .../migrations/0002_auto_20210510_1246.py | 38 +- .../migrations/0003_auto_20210607_1226.py | 9 +- src/ralph/accessories/models.py | 127 +- src/ralph/accessories/tests/factories.py | 4 +- src/ralph/accounts/__init__.py | 2 +- src/ralph/accounts/admin.py | 345 +++-- src/ralph/accounts/api.py | 49 +- src/ralph/accounts/api_simple.py | 12 +- src/ralph/accounts/apps.py | 6 +- src/ralph/accounts/helpers.py | 145 +- src/ralph/accounts/ldap.py | 69 +- src/ralph/accounts/ldap_helpers.py | 29 +- .../accounts/management/commands/ldap_sync.py | 117 +- src/ralph/accounts/migrations/0001_initial.py | 504 ++++++- .../migrations/0002_auto_20151204_0758.py | 9 +- .../migrations/0003_region_country.py | 249 +++- .../0004_region_stocktaking_enabled.py | 7 +- .../migrations/0005_auto_20170814_1636.py | 13 +- .../0006_remove_ralphuser_gender.py | 9 +- .../migrations/0007_auto_20240506_1128.py | 21 +- .../migrations/0008_auto_20240507_1422.py | 16 +- .../migrations/0009_auto_20240621_1217.py | 11 +- .../migrations/0010_auto_20241030_1235.py | 11 +- src/ralph/accounts/models.py | 68 +- src/ralph/accounts/tests/factories.py | 23 +- src/ralph/accounts/tests/tests.py | 174 +-- src/ralph/accounts/urls.py | 19 +- src/ralph/accounts/views.py | 146 +- src/ralph/admin/__init__.py | 2 +- src/ralph/admin/apps.py | 7 +- src/ralph/admin/autocomplete.py | 140 +- src/ralph/admin/autocomplete_urls.py | 4 +- src/ralph/admin/decorators.py | 23 +- src/ralph/admin/fields.py | 57 +- src/ralph/admin/filters.py | 392 +++--- src/ralph/admin/helpers.py | 27 +- src/ralph/admin/m2m.py | 3 +- src/ralph/admin/mixins.py | 262 ++-- src/ralph/admin/signals.py | 2 +- src/ralph/admin/sites.py | 52 +- src/ralph/admin/sitetrees.py | 521 ++++---- .../admin/templatetags/admin_change_list.py | 11 +- .../admin/templatetags/dashboard_tags.py | 244 ++-- src/ralph/admin/templatetags/ralph_tags.py | 53 +- src/ralph/admin/tests/test_m2m.py | 83 +- src/ralph/admin/tests/test_menu.py | 2 +- src/ralph/admin/tests/test_templatetags.py | 28 +- src/ralph/admin/tests/tests_autocomplete.py | 50 +- src/ralph/admin/tests/tests_fields.py | 128 +- src/ralph/admin/tests/tests_filters.py | 197 ++- src/ralph/admin/tests/tests_functional.py | 215 ++- src/ralph/admin/tests/tests_helpers.py | 37 +- src/ralph/admin/tests/tests_multiadd.py | 184 +-- src/ralph/admin/tests/tests_tags.py | 13 +- src/ralph/admin/tests/tests_views.py | 360 +++-- src/ralph/admin/tests/tests_widgets.py | 18 +- src/ralph/admin/views/extra.py | 112 +- src/ralph/admin/views/main.py | 29 +- src/ralph/admin/views/multiadd.py | 99 +- src/ralph/admin/widgets.py | 214 ++- src/ralph/api/__init__.py | 8 +- src/ralph/api/fields.py | 27 +- src/ralph/api/filters.py | 216 +-- src/ralph/api/permissions.py | 8 +- src/ralph/api/relations.py | 3 +- src/ralph/api/routers.py | 9 +- src/ralph/api/serializers.py | 93 +- src/ralph/api/tests/_base.py | 72 +- src/ralph/api/tests/api.py | 38 +- src/ralph/api/tests/test_fields.py | 28 +- src/ralph/api/tests/test_filters.py | 231 ++-- src/ralph/api/tests/test_rendering.py | 56 +- src/ralph/api/tests/test_routers.py | 18 +- src/ralph/api/tests/test_serializers.py | 96 +- src/ralph/api/tests/test_viewsets.py | 49 +- src/ralph/api/utils.py | 56 +- src/ralph/api/viewsets.py | 63 +- src/ralph/apps.py | 4 +- src/ralph/assets/__init__.py | 2 +- src/ralph/assets/_migration_helpers.py | 104 +- src/ralph/assets/admin.py | 256 ++-- src/ralph/assets/api/filters.py | 7 +- src/ralph/assets/api/routers.py | 42 +- src/ralph/assets/api/serializers.py | 179 +-- src/ralph/assets/api/serializers_dchosts.py | 35 +- src/ralph/assets/api/views.py | 18 +- src/ralph/assets/apps.py | 7 +- src/ralph/assets/country_utils.py | 299 ++++- src/ralph/assets/invoice_report.py | 134 +- src/ralph/assets/migrations/0001_initial.py | 860 +++++++++--- .../migrations/0002_auto_20151125_1354.py | 99 +- .../migrations/0003_auto_20151126_2205.py | 12 +- .../migrations/0004_auto_20151204_0758.py | 29 +- .../0005_category_depreciation_rate.py | 15 +- .../0006_category_show_buyout_date.py | 7 +- .../migrations/0007_auto_20160122_1022.py | 45 +- .../migrations/0008_auto_20160122_1429.py | 27 +- .../migrations/0009_auto_20160307_1138.py | 17 +- .../migrations/0010_auto_20160405_1531.py | 7 +- .../migrations/0011_auto_20160603_0742.py | 27 +- .../migrations/0012_auto_20160606_1409.py | 283 +++- .../migrations/0013_auto_20160615_2140.py | 23 +- src/ralph/assets/migrations/0014_memory.py | 70 +- .../migrations/0015_auto_20160701_0952.py | 55 +- .../migrations/0016_fibrechannelcard.py | 98 +- src/ralph/assets/migrations/0017_processor.py | 68 +- src/ralph/assets/migrations/0018_disk.py | 88 +- .../migrations/0019_auto_20160719_1443.py | 24 +- .../migrations/0020_auto_20160803_0712.py | 24 +- .../migrations/0021_auto_20160810_1410.py | 16 +- .../migrations/0022_auto_20160823_0921.py | 35 +- .../0023_category_allow_deployment.py | 7 +- .../migrations/0024_auto_20170322_1148.py | 38 +- .../migrations/0025_auto_20170331_1341.py | 13 +- .../migrations/0026_auto_20170510_0840.py | 36 +- .../migrations/0027_asset_buyout_date.py | 14 +- .../migrations/0028_auto_20180730_1135.py | 49 +- .../migrations/0029_asset_start_usage.py | 13 +- .../migrations/0030_auto_20200528_1301.py | 9 +- .../migrations/0031_auto_20200728_1326.py | 14 +- .../migrations/0032_auto_20200909_1012.py | 219 ++- .../migrations/0033_auto_20211115_1125.py | 17 +- .../migrations/0034_auto_20240304_1511.py | 15 +- .../migrations/0035_auto_20240506_1633.py | 7 +- .../migrations/0036_auto_20240621_1200.py | 27 +- .../migrations/0036_auto_20240904_1126.py | 44 +- .../migrations/0037_auto_20240621_1217.py | 15 +- .../migrations/0037_auto_20241008_1003.py | 22 +- .../migrations/0038_merge_20240916_1249.py | 8 +- .../migrations/0039_merge_20241008_1243.py | 8 +- src/ralph/assets/models/__init__.py | 69 +- src/ralph/assets/models/assets.py | 237 ++-- src/ralph/assets/models/base.py | 51 +- src/ralph/assets/models/choices.py | 106 +- src/ralph/assets/models/components.py | 163 ++- src/ralph/assets/models/configuration.py | 59 +- src/ralph/assets/signals.py | 29 +- src/ralph/assets/subscribers.py | 120 +- src/ralph/assets/tests/factories.py | 214 +-- src/ralph/assets/tests/test_api.py | 1181 +++++++---------- src/ralph/assets/tests/test_models.py | 30 +- src/ralph/assets/tests/test_signals.py | 74 +- src/ralph/assets/tests/test_subscribers.py | 187 ++- src/ralph/assets/utils.py | 34 +- src/ralph/assets/views.py | 37 +- src/ralph/attachments/admin.py | 14 +- src/ralph/attachments/forms.py | 31 +- src/ralph/attachments/helpers.py | 13 +- .../attachments/migrations/0001_initial.py | 91 +- .../migrations/0002_auto_20151125_1354.py | 15 +- .../migrations/0003_auto_20160121_1346.py | 34 +- src/ralph/attachments/models.py | 42 +- src/ralph/attachments/tests/__init__.py | 8 +- src/ralph/attachments/tests/test_models.py | 24 +- src/ralph/attachments/urls.py | 4 +- src/ralph/attachments/utils.py | 6 +- src/ralph/attachments/views.py | 35 +- src/ralph/back_office/__init__.py | 2 +- src/ralph/back_office/admin.py | 332 +++-- src/ralph/back_office/api.py | 36 +- src/ralph/back_office/apps.py | 4 +- src/ralph/back_office/helpers.py | 18 +- .../back_office/migrations/0001_initial.py | 184 ++- .../migrations/0002_auto_20151125_1354.py | 27 +- .../migrations/0003_auto_20151204_0758.py | 9 +- .../0004_warehouse_stocktaking_enabled.py | 7 +- .../0005_warehouse_stocktaking_tag_suffix.py | 9 +- .../migrations/0006_auto_20160902_1238.py | 9 +- .../migrations/0007_auto_20180105_0910.py | 27 +- .../migrations/0008_auto_20180801_1157.py | 28 +- .../migrations/0009_auto_20181016_1252.py | 29 +- .../migrations/0010_backofficeasset_imei2.py | 13 +- .../migrations/0011_auto_20190517_1115.py | 21 +- .../migrations/0012_auto_20210318_1230.py | 30 +- .../migrations/0013_auto_20220421_1202.py | 31 +- .../migrations/0014_auto_20221108_1007.py | 32 +- .../migrations/0015_auto_20221207_1445.py | 34 +- .../migrations/0016_auto_20221220_1210.py | 34 +- .../migrations/0017_auto_20230112_0949.py | 36 +- .../migrations/0018_auto_20230206_1020.py | 37 +- ...0019_backofficeasset_last_status_change.py | 11 +- .../migrations/0020_auto_20230419_1223.py | 15 +- .../migrations/0021_auto_20230511_1202.py | 38 +- .../migrations/0022_auto_20230616_1235.py | 39 +- .../migrations/0023_auto_20240223_1018.py | 40 +- .../migrations/0024_auto_20240621_1217.py | 7 +- src/ralph/back_office/models.py | 441 +++--- src/ralph/back_office/tests/factories.py | 47 +- src/ralph/back_office/tests/test_api.py | 141 +- src/ralph/back_office/tests/test_helpers.py | 3 +- src/ralph/back_office/tests/test_models.py | 413 +++--- src/ralph/back_office/views.py | 88 +- src/ralph/configuration_management/api.py | 51 +- .../migrations/0001_initial.py | 47 +- .../migrations/0002_auto_20170622_1254.py | 14 +- .../migrations/0003_scmstatuscheck_ok.py | 14 +- src/ralph/configuration_management/models.py | 21 +- .../tests/factories.py | 1 - .../tests/test_api.py | 117 +- src/ralph/configuration_management/views.py | 53 +- src/ralph/dashboards/admin.py | 112 +- src/ralph/dashboards/admin_filters.py | 14 +- src/ralph/dashboards/api/routers.py | 2 +- src/ralph/dashboards/api/serializers.py | 10 +- src/ralph/dashboards/api/views.py | 7 +- src/ralph/dashboards/filter_parser.py | 23 +- src/ralph/dashboards/helpers.py | 4 +- .../commands/push_graphs_to_statsd.py | 7 +- .../dashboards/migrations/0001_initial.py | 123 +- .../migrations/0002_auto_20170509_1404.py | 11 +- .../migrations/0003_graph_push_to_statsd.py | 11 +- .../migrations/0004_auto_20170926_1547.py | 17 +- .../migrations/0005_auto_20170927_1505.py | 18 +- .../migrations/0006_auto_20171221_0959.py | 28 +- .../migrations/0007_auto_20240723_1148.py | 10 +- src/ralph/dashboards/models.py | 196 ++- src/ralph/dashboards/renderers.py | 153 +-- .../dashboards/templatetags/graph_tags.py | 4 +- src/ralph/dashboards/tests/factories.py | 24 +- src/ralph/dashboards/tests/test_api.py | 18 +- src/ralph/dashboards/tests/test_models.py | 115 +- src/ralph/dashboards/tests/test_parser.py | 298 ++--- src/ralph/dashboards/tests/test_renderer.py | 30 +- src/ralph/dashboards/urls.py | 4 +- src/ralph/dashboards/views.py | 20 +- src/ralph/data_center/__init__.py | 2 +- src/ralph/data_center/admin.py | 673 ++++++---- src/ralph/data_center/api/routers.py | 24 +- src/ralph/data_center/api/serializers.py | 35 +- src/ralph/data_center/api/views.py | 105 +- src/ralph/data_center/apps.py | 5 +- src/ralph/data_center/forms.py | 61 +- .../data_center/migrations/0001_initial.py | 1032 +++++++++++--- .../migrations/0002_auto_20151125_1354.py | 27 +- .../migrations/0003_auto_20151126_2222.py | 31 +- .../migrations/0004_auto_20151204_0758.py | 13 +- .../migrations/0005_auto_20160121_1133.py | 9 +- .../migrations/0006_rack_require_position.py | 12 +- .../migrations/0007_auto_20160225_1818.py | 22 +- .../0008_datacenter_show_on_dashboard.py | 7 +- .../migrations/0009_auto_20160419_1003.py | 104 +- ...010_visualization_fields_for_serverroom.py | 51 +- .../migrations/0011_change_networks_models.py | 158 ++- .../0012_custom_move_to_networks.py | 36 +- .../migrations/0013_auto_20160606_1438.py | 60 +- .../0014_custom_move_managment_to_networks.py | 41 +- .../migrations/0015_auto_20160615_2140.py | 13 +- .../migrations/0016_diskshare_model_name.py | 11 +- .../migrations/0017_auto_20160719_1530.py | 19 +- .../migrations/0018_auto_20160729_1401.py | 14 +- .../data_center/migrations/0019_dchost.py | 16 +- .../migrations/0020_auto_20160907_1116.py | 39 +- .../migrations/0021_auto_20161003_0751.py | 29 +- .../migrations/0022_auto_20161206_1521.py | 22 +- .../migrations/0023_rack_reverse_ordering.py | 16 +- .../migrations/0024_auto_20170331_1341.py | 14 +- .../migrations/0025_auto_20170510_1122.py | 23 +- .../migrations/0026_auto_20170614_1237.py | 13 +- .../migrations/0027_auto_20230831_1234.py | 309 ++++- .../migrations/0028_auto_20230831_1354.py | 22 +- .../migrations/0029_auto_20230920_1102.py | 22 +- .../migrations/0030_auto_20240221_1004.py | 22 +- .../migrations/0031_auto_20240304_1642.py | 9 +- .../migrations/0032_auto_20240521_1542.py | 15 +- .../migrations/0033_auto_20240621_1217.py | 30 +- .../migrations/0034_auto_20240628_1207.py | 19 +- src/ralph/data_center/models/__init__.py | 44 +- src/ralph/data_center/models/choices.py | 22 +- src/ralph/data_center/models/components.py | 64 +- src/ralph/data_center/models/mixins.py | 22 +- src/ralph/data_center/models/physical.py | 549 ++++---- src/ralph/data_center/models/virtual.py | 81 +- src/ralph/data_center/publishers.py | 39 +- src/ralph/data_center/subscribers.py | 175 ++- src/ralph/data_center/tests/factories.py | 121 +- src/ralph/data_center/tests/test_admin.py | 196 ++- src/ralph/data_center/tests/test_api.py | 710 +++++----- src/ralph/data_center/tests/test_forms.py | 266 ++-- src/ralph/data_center/tests/test_models.py | 334 ++--- .../data_center/tests/test_publishers.py | 21 +- src/ralph/data_center/tests/test_signals.py | 14 +- .../data_center/tests/test_subscribers.py | 126 +- src/ralph/data_center/tests/test_view.py | 181 ++- src/ralph/data_center/views.py | 33 +- src/ralph/data_importer/fields.py | 63 +- .../management/commands/create_network.py | 85 +- .../commands/create_preboot_configuration.py | 53 +- .../commands/create_server_model.py | 68 +- .../management/commands/create_transitions.py | 66 +- .../management/commands/demodata.py | 336 +++-- .../management/commands/import_attachments.py | 132 +- .../management/commands/importer.py | 142 +- .../management/commands/initial_data.py | 129 +- .../data_importer/migrations/0001_initial.py | 43 +- .../migrations/0002_auto_20151125_1354.py | 15 +- .../migrations/0003_auto_20160624_1217.py | 11 +- .../migrations/0004_auto_20160728_1046.py | 11 +- .../0005_importedobjects_old_ci_uid.py | 11 +- src/ralph/data_importer/mixins.py | 46 +- src/ralph/data_importer/models.py | 24 +- src/ralph/data_importer/resources.py | 512 ++++--- .../data_importer/tests/test_commands.py | 450 +++---- .../data_importer/tests/test_demo_data.py | 3 +- src/ralph/data_importer/tests/test_export.py | 80 +- src/ralph/data_importer/tests/test_fields.py | 99 +- src/ralph/data_importer/tests/test_widgets.py | 42 +- src/ralph/data_importer/widgets.py | 78 +- src/ralph/dc_view/__init__.py | 2 +- src/ralph/dc_view/apps.py | 4 +- .../dc_view/serializers/models_serializer.py | 154 ++- src/ralph/dc_view/tests.py | 125 +- src/ralph/dc_view/urls/api.py | 4 +- src/ralph/dc_view/urls/ui.py | 10 +- src/ralph/dc_view/views/api.py | 26 +- src/ralph/dc_view/views/ui.py | 20 +- src/ralph/deployment/__init__.py | 2 +- src/ralph/deployment/admin.py | 71 +- src/ralph/deployment/apps.py | 6 +- src/ralph/deployment/deployment.py | 418 +++--- src/ralph/deployment/forms.py | 28 +- .../deployment/migrations/0001_initial.py | 174 ++- .../migrations/0002_auto_20160816_1112.py | 13 +- .../migrations/0003_auto_20161124_1317.py | 23 +- .../migrations/0004_auto_20161128_1359.py | 28 +- .../migrations/0005_auto_20180625_1257.py | 12 +- .../migrations/0006_auto_20211019_1456.py | 20 +- .../migrations/0007_auto_20240506_1633.py | 15 +- .../migrations/0008_auto_20240705_1210.py | 15 +- .../migrations/0009_auto_20240924_1133.py | 11 +- src/ralph/deployment/mixins.py | 51 +- src/ralph/deployment/models.py | 107 +- src/ralph/deployment/tests/factories.py | 6 +- src/ralph/deployment/tests/test_deployment.py | 340 +++-- src/ralph/deployment/tests/test_forms.py | 7 +- .../deployment/tests/test_transitions.py | 470 +++---- src/ralph/deployment/urls.py | 56 +- src/ralph/deployment/utils.py | 214 ++- src/ralph/deployment/views.py | 42 +- src/ralph/dhcp/admin.py | 76 +- src/ralph/dhcp/api.py | 4 +- src/ralph/dhcp/migrations/0001_initial.py | 59 +- src/ralph/dhcp/migrations/0002_dhcpentry.py | 16 +- .../0003_dhcpserver_network_environment.py | 17 +- .../migrations/0004_add_dns_server_group.py | 67 +- .../migrations/0005_change_related_name.py | 23 +- .../0006_remove_dnsserver_is_default.py | 9 +- src/ralph/dhcp/models.py | 62 +- src/ralph/dhcp/tests/factories.py | 13 +- src/ralph/dhcp/tests/test_agent.py | 87 +- src/ralph/dhcp/tests/test_models.py | 3 +- src/ralph/dhcp/tests/test_views.py | 108 +- src/ralph/dhcp/urls.py | 18 +- src/ralph/dhcp/views.py | 159 +-- src/ralph/dns/__init__.py | 2 +- src/ralph/dns/apps.py | 5 +- src/ralph/dns/dnsaas.py | 165 ++- src/ralph/dns/forms.py | 42 +- .../commands/dns_find_inconsistencies.py | 96 +- src/ralph/dns/publishers.py | 10 +- src/ralph/dns/tests.py | 777 ++++++----- src/ralph/dns/views.py | 65 +- src/ralph/domains/__init__.py | 2 +- src/ralph/domains/admin.py | 118 +- src/ralph/domains/api.py | 25 +- src/ralph/domains/apps.py | 5 +- src/ralph/domains/forms.py | 6 +- src/ralph/domains/migrations/0001_initial.py | 180 ++- .../migrations/0002_auto_20151125_1354.py | 27 +- .../migrations/0003_auto_20160823_0921.py | 14 +- .../migrations/0004_auto_20160907_1100.py | 24 +- .../migrations/0005_auto_20170523_1214.py | 97 +- .../migrations/0006_auto_20180725_1216.py | 44 +- .../migrations/0007_auto_20200909_1012.py | 219 ++- .../migrations/0008_auto_20240621_1011.py | 7 +- src/ralph/domains/models/__init__.py | 12 +- src/ralph/domains/models/domains.py | 99 +- src/ralph/domains/publishers.py | 31 +- src/ralph/domains/tests/factories.py | 20 +- src/ralph/domains/tests/tests.py | 52 +- src/ralph/health_check.py | 20 +- src/ralph/helpers.py | 22 +- src/ralph/lib/custom_fields/api/routers.py | 18 +- .../lib/custom_fields/api/serializers.py | 4 +- src/ralph/lib/transitions/api/routers.py | 2 +- src/ralph/licences/admin.py | 208 ++- src/ralph/licences/api.py | 72 +- src/ralph/licences/api_simple.py | 10 +- src/ralph/licences/migrations/0001_initial.py | 320 ++++- .../migrations/0002_auto_20151204_1325.py | 16 +- .../migrations/0003_auto_20160823_0921.py | 51 +- .../0004_licence_depreciation_rate.py | 16 +- .../migrations/0005_licence_start_usage.py | 13 +- .../migrations/0006_auto_20200909_1115.py | 219 ++- .../migrations/0007_auto_20240506_1633.py | 7 +- .../migrations/0008_auto_20240628_1207.py | 20 +- src/ralph/licences/models.py | 171 ++- src/ralph/licences/tests/factories.py | 48 +- src/ralph/licences/tests/test_api.py | 87 +- src/ralph/licences/tests/test_functional.py | 83 +- src/ralph/licences/tests/tests_models.py | 56 +- src/ralph/networks/__init__.py | 2 +- src/ralph/networks/admin.py | 344 +++-- src/ralph/networks/api.py | 64 +- src/ralph/networks/api_simple.py | 4 +- src/ralph/networks/apps.py | 19 +- src/ralph/networks/fields.py | 6 +- src/ralph/networks/filters.py | 40 +- src/ralph/networks/forms.py | 133 +- src/ralph/networks/migrations/0001_initial.py | 445 +++++-- .../migrations/0002_add_ethernet_field.py | 15 +- .../migrations/0003_custom_link_ips_to_eth.py | 19 +- .../migrations/0004_auto_20160606_1512.py | 219 ++- .../migrations/0005_network_gateway.py | 16 +- ...networkenvironment_use_hostname_counter.py | 12 +- .../migrations/0007_auto_20160804_1409.py | 16 +- .../migrations/0008_auto_20160808_0719.py | 92 +- .../migrations/0009_auto_20160823_0921.py | 17 +- .../migrations/0010_auto_20170216_1230.py | 16 +- .../migrations/0011_add_dns_servers_group.py | 45 +- .../0012_remove_network_dns_servers.py | 9 +- .../migrations/0013_auto_20171006_0947.py | 14 +- .../migrations/0014_auto_20171009_1030.py | 15 +- .../migrations/0015_auto_20211115_1125.py | 17 +- .../migrations/0016_auto_20240621_1200.py | 15 +- .../migrations/0016_auto_20240924_1155.py | 11 +- .../migrations/0017_merge_20240925_1101.py | 8 +- src/ralph/networks/models/__init__.py | 14 +- src/ralph/networks/models/choices.py | 4 +- src/ralph/networks/models/networks.py | 312 ++--- src/ralph/networks/receivers.py | 28 +- src/ralph/networks/tests/factories.py | 37 +- src/ralph/networks/tests/test_admin.py | 20 +- src/ralph/networks/tests/test_api.py | 149 +-- src/ralph/networks/tests/test_filters.py | 67 +- src/ralph/networks/tests/test_forms.py | 794 +++++------ src/ralph/networks/tests/test_models.py | 481 +++---- src/ralph/networks/tests/test_receivers.py | 44 +- src/ralph/networks/views.py | 44 +- src/ralph/notifications/__init__.py | 2 +- src/ralph/notifications/apps.py | 12 +- src/ralph/notifications/sender.py | 54 +- src/ralph/notifications/test_notification.py | 31 +- src/ralph/operations/__init__.py | 2 +- src/ralph/operations/admin.py | 145 +- src/ralph/operations/api.py | 44 +- src/ralph/operations/apps.py | 7 +- .../operations/changemanagement/exceptions.py | 2 +- src/ralph/operations/changemanagement/jira.py | 28 +- .../changemanagement/subscribtions.py | 53 +- src/ralph/operations/filters.py | 11 +- .../operations/migrations/0001_initial.py | 188 ++- .../migrations/0002_auto_20151218_1029.py | 63 +- .../migrations/0003_auto_20160303_1114.py | 30 +- .../migrations/0004_auto_20160307_1138.py | 17 +- .../migrations/0005_auto_20170323_1425.py | 18 +- .../migrations/0006_auto_20170323_1530.py | 21 +- .../migrations/0007_auto_20170328_1728.py | 7 +- .../migrations/0008_auto_20170331_0952.py | 16 +- .../migrations/0009_auto_20170403_1112.py | 18 +- .../migrations/0010_auto_20170410_1031.py | 66 +- .../migrations/0011_operation_reporter.py | 16 +- .../migrations/0012_auto_20211206_1347.py | 9 +- .../migrations/0013_auto_20240621_1200.py | 15 +- .../migrations/0013_auto_20241002_1122.py | 14 +- .../migrations/0014_merge_20241008_1131.py | 8 +- src/ralph/operations/models.py | 87 +- src/ralph/operations/tests/factories.py | 25 +- src/ralph/operations/tests/test_admin.py | 3 +- src/ralph/operations/tests/test_api.py | 61 +- .../operations/tests/test_event_receiver.py | 49 +- .../operations/tests/test_jira_processor.py | 45 +- src/ralph/operations/tests/test_models.py | 9 +- src/ralph/operations/views.py | 33 +- src/ralph/reports/__init__.py | 2 +- src/ralph/reports/admin.py | 6 +- src/ralph/reports/apps.py | 4 +- src/ralph/reports/base.py | 16 +- src/ralph/reports/factories.py | 9 +- src/ralph/reports/forms.py | 8 +- src/ralph/reports/helpers.py | 63 +- .../commands/send_data_center_asset_export.py | 52 +- src/ralph/reports/migrations/0001_initial.py | 120 +- .../migrations/0002_auto_20151125_1354.py | 39 +- .../migrations/0003_auto_20151204_0758.py | 13 +- .../migrations/0004_reportlanguage_default.py | 7 +- src/ralph/reports/models.py | 27 +- src/ralph/reports/resources.py | 95 +- src/ralph/reports/tests/test_email_reports.py | 36 +- src/ralph/reports/tests/test_reports.py | 417 +++--- src/ralph/reports/tests/test_resources.py | 51 +- src/ralph/reports/urls.py | 34 +- src/ralph/reports/views.py | 568 ++++---- src/ralph/security/__init__.py | 2 +- src/ralph/security/api.py | 46 +- src/ralph/security/apps.py | 6 +- .../management/commands/update_is_patched.py | 27 +- src/ralph/security/migrations/0001_initial.py | 131 +- .../migrations/0002_auto_20160307_1138.py | 29 +- .../migrations/0003_auto_20170110_1352.py | 9 +- .../migrations/0004_auto_20170321_1332.py | 24 +- .../migrations/0005_auto_20170322_0902.py | 11 +- .../0006_securityscan_is_patched.py | 7 +- .../migrations/0007_auto_20170331_0934.py | 19 +- .../0008_vulnerability_display_name.py | 11 +- src/ralph/security/models.py | 26 +- src/ralph/security/tests/factories.py | 8 +- src/ralph/security/tests/test_api.py | 325 +++-- src/ralph/security/tests/test_serializers.py | 49 +- src/ralph/security/transitions.py | 8 +- src/ralph/security/views.py | 47 +- src/ralph/settings/base.py | 761 +++++------ src/ralph/settings/dev.py | 60 +- src/ralph/settings/hooks.py | 5 +- src/ralph/settings/prod.py | 89 +- src/ralph/settings/test.py | 87 +- src/ralph/signals.py | 8 +- src/ralph/sim_cards/admin.py | 102 +- src/ralph/sim_cards/api.py | 39 +- src/ralph/sim_cards/forms.py | 2 +- .../sim_cards/migrations/0001_initial.py | 218 ++- .../migrations/0002_auto_20181123_1138.py | 30 +- .../migrations/0003_auto_20181212_1254.py | 9 +- .../migrations/0004_simcard_property_of.py | 16 +- src/ralph/sim_cards/models.py | 270 ++-- src/ralph/sim_cards/tests/factories.py | 26 +- src/ralph/sim_cards/tests/test_admin.py | 68 +- src/ralph/ssl_certificates/__init__.py | 2 +- src/ralph/ssl_certificates/admin.py | 57 +- src/ralph/ssl_certificates/api.py | 21 +- src/ralph/ssl_certificates/apps.py | 3 +- .../commands/import_ssl_certificates.py | 42 +- .../update_dns_service_env_from_dnsaas.py | 34 +- .../migrations/0001_initial.py | 101 +- .../migrations/0002_auto_20180522_1244.py | 27 +- ...move_sslcertificate_service_environment.py | 9 +- .../migrations/0004_auto_20181031_1042.py | 13 +- .../migrations/0005_auto_20200909_1012.py | 219 ++- ...6_sslcertificate_certificate_repository.py | 14 +- .../migrations/0007_auto_20240621_1217.py | 7 +- src/ralph/ssl_certificates/models.py | 38 +- src/ralph/ssl_certificates/tests/api.py | 35 +- src/ralph/ssl_certificates/tests/factories.py | 11 +- src/ralph/ssl_certificates/tests/tests.py | 70 +- src/ralph/supports/admin.py | 263 ++-- src/ralph/supports/api.py | 44 +- src/ralph/supports/migrations/0001_initial.py | 161 ++- .../migrations/0002_auto_20151204_0758.py | 9 +- .../migrations/0003_auto_20151204_1325.py | 31 +- .../migrations/0004_auto_20151229_0925.py | 9 +- .../migrations/0005_auto_20160105_1222.py | 13 +- .../migrations/0006_auto_20160615_0805.py | 31 +- .../migrations/0007_auto_20160823_0921.py | 31 +- .../migrations/0008_auto_20200909_1012.py | 219 ++- .../migrations/0009_auto_20240506_1633.py | 7 +- .../migrations/0010_auto_20240628_1207.py | 18 +- .../migrations/0010_auto_20241002_1122.py | 13 +- .../migrations/0011_merge_20241008_1131.py | 8 +- src/ralph/supports/models.py | 87 +- src/ralph/supports/tests/factories.py | 45 +- src/ralph/supports/tests/test_api.py | 68 +- src/ralph/supports/tests/test_autocomplete.py | 51 +- src/ralph/tests/__init__.py | 4 +- src/ralph/tests/admin.py | 22 +- src/ralph/tests/factories.py | 14 +- src/ralph/tests/migrations/0001_initial.py | 130 +- .../migrations/0002_auto_20160119_0914.py | 31 +- src/ralph/tests/migrations/0003_bar.py | 25 +- src/ralph/tests/migrations/0004_car_foos.py | 9 +- src/ralph/tests/migrations/0005_bar_foos.py | 11 +- .../migrations/0006_auto_20160607_0842.py | 66 +- .../migrations/0007_auto_20160808_1324.py | 7 +- .../migrations/0008_auto_20200909_1322.py | 219 ++- .../migrations/0009_auto_20240621_1009.py | 7 +- .../migrations/0010_auto_20240621_1217.py | 13 +- .../migrations/0011_auto_20240621_1231.py | 13 +- .../migrations/0012_auto_20240621_1355.py | 13 +- .../migrations/0013_auto_20240627_1512.py | 13 +- .../migrations/0014_auto_20240628_1213.py | 16 +- .../migrations/0015_auto_20240918_1428.py | 7 +- src/ralph/tests/mixins.py | 4 +- src/ralph/tests/models.py | 103 +- src/ralph/trade_marks/admin.py | 293 ++-- src/ralph/trade_marks/forms.py | 4 +- .../trade_marks/migrations/0001_initial.py | 203 ++- .../migrations/0002_auto_20181005_1446.py | 12 +- .../migrations/0003_trademark_image.py | 11 +- .../migrations/0004_auto_20190221_0923.py | 343 ++++- .../migrations/0005_auto_20190312_0931.py | 251 +++- .../migrations/0006_trademark_valid_from.py | 7 +- .../migrations/0007_auto_20190813_0914.py | 7 +- .../migrations/0008_auto_20210625_0738.py | 429 ++++-- .../migrations/0009_auto_20210630_1719.py | 150 ++- .../migrations/0010_auto_20210702_1129.py | 57 +- .../migrations/0011_trademarkkind.py | 9 +- .../0012_populate_trademark_kinds.py | 13 +- .../migrations/0013_auto_20211206_1400.py | 14 +- .../migrations/0014_auto_20211207_1118.py | 15 +- .../migrations/0015_auto_20221020_1340.py | 191 ++- .../migrations/0016_auto_20240621_1217.py | 19 +- src/ralph/trade_marks/models.py | 227 ++-- src/ralph/trade_marks/tests/factories.py | 34 +- src/ralph/urls/__init__.py | 2 +- src/ralph/urls/base.py | 89 +- src/ralph/urls/dev.py | 8 +- src/ralph/urls/test.py | 11 +- src/ralph/virtual/admin.py | 506 ++++--- src/ralph/virtual/api.py | 151 ++- src/ralph/virtual/cloudsync.py | 28 +- src/ralph/virtual/forms.py | 10 +- .../management/commands/openstack_sync.py | 473 +++---- src/ralph/virtual/migrations/0001_initial.py | 45 +- .../migrations/0002_auto_20160226_0826.py | 167 ++- .../migrations/0003_auto_20160606_1442.py | 98 +- .../migrations/0004_virtualserver_status.py | 19 +- .../migrations/0005_auto_20160615_2140.py | 13 +- .../0006_virtualcomponent_model_name.py | 11 +- .../migrations/0007_auto_20160630_0949.py | 22 +- .../migrations/0008_auto_20160823_0921.py | 23 +- .../migrations/0009_auto_20170522_0745.py | 9 +- .../migrations/0010_auto_20181018_0822.py | 11 +- .../0011_cloudprovider_client_config.py | 18 +- .../virtual/migrations/0012_cloudimage.py | 31 +- .../migrations/0013_auto_20190625_1239.py | 9 +- .../migrations/0014_auto_20240621_1009.py | 7 +- .../migrations/0015_auto_20240621_1217.py | 15 +- src/ralph/virtual/models.py | 193 ++- src/ralph/virtual/processors/noop.py | 2 +- src/ralph/virtual/tests/factories.py | 91 +- .../virtual/tests/samples/openstack_data.py | 247 ++-- src/ralph/virtual/tests/test_admin.py | 73 +- src/ralph/virtual/tests/test_api.py | 583 ++++---- src/ralph/virtual/tests/test_cloudsync.py | 54 +- src/ralph/virtual/tests/test_models.py | 130 +- .../virtual/tests/test_openstack_sync.py | 360 +++-- src/ralph/virtual/urls.py | 4 +- 650 files changed, 28816 insertions(+), 22045 deletions(-) diff --git a/src/ralph/__init__.py b/src/ralph/__init__.py index 5adeaeba19..4439b3da9f 100644 --- a/src/ralph/__init__.py +++ b/src/ralph/__init__.py @@ -1,11 +1,11 @@ from django.db.models.options import Options -__version__ = '3.0.0' +__version__ = "3.0.0" def monkey_options_init(self, meta, app_label): self._old__init__(meta, app_label) - self.default_permissions = ('add', 'change', 'delete', 'view') + self.default_permissions = ("add", "change", "delete", "view") Options._old__init__ = Options.__init__ diff --git a/src/ralph/__main__.py b/src/ralph/__main__.py index d2f464da0e..ca821d0c73 100755 --- a/src/ralph/__main__.py +++ b/src/ralph/__main__.py @@ -3,11 +3,11 @@ import sys -def main(settings_module='ralph.settings', force=False): +def main(settings_module="ralph.settings", force=False): if force: - os.environ['DJANGO_SETTINGS_MODULE'] = settings_module + os.environ["DJANGO_SETTINGS_MODULE"] = settings_module else: - os.environ.setdefault('DJANGO_SETTINGS_MODULE', settings_module) + os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_module) from django.core.management import execute_from_command_line @@ -15,18 +15,18 @@ def main(settings_module='ralph.settings', force=False): def dev(): - main('ralph.settings.dev') + main("ralph.settings.dev") def test(): # test only with test settings, not local (or any set by environment # variable DJANGO_SETTINGS_MODULE) - main('ralph.settings.test', force=True) + main("ralph.settings.test", force=True) def prod(): - main('ralph.settings.prod') + main("ralph.settings.prod") -if __name__ == '__main__': - main('ralph.settings.prod') +if __name__ == "__main__": + main("ralph.settings.prod") diff --git a/src/ralph/access_cards/admin.py b/src/ralph/access_cards/admin.py index 3554a175b0..6c6a8bda75 100644 --- a/src/ralph/access_cards/admin.py +++ b/src/ralph/access_cards/admin.py @@ -9,69 +9,81 @@ @register(AccessCard) class AccessCardAdmin(TransitionAdminMixin, RalphAdmin): show_transition_history = True - list_display = ['status', 'visual_number', 'system_number', 'user', - 'owner', 'get_employee_id', 'get_employee_company'] - list_select_related = ['user', 'owner'] - raw_id_fields = ['user', 'owner', 'region'] - list_filter = ['status', 'issue_date', 'visual_number', - 'system_number', 'user', 'owner', 'user__segment', - 'user__company', 'user__department', 'user__employee_id', - 'access_zones', 'notes'] - search_fields = ['visual_number', 'system_number', 'user__first_name', - 'user__last_name', 'user__username'] - readonly_fields = ['get_employee_id', 'get_employee_company'] + list_display = [ + "status", + "visual_number", + "system_number", + "user", + "owner", + "get_employee_id", + "get_employee_company", + ] + list_select_related = ["user", "owner"] + raw_id_fields = ["user", "owner", "region"] + list_filter = [ + "status", + "issue_date", + "visual_number", + "system_number", + "user", + "owner", + "user__segment", + "user__company", + "user__department", + "user__employee_id", + "access_zones", + "notes", + ] + search_fields = [ + "visual_number", + "system_number", + "user__first_name", + "user__last_name", + "user__username", + ] + readonly_fields = ["get_employee_id", "get_employee_company"] fieldsets = ( ( - _('Access Card Info'), + _("Access Card Info"), { - 'fields': ('visual_number', 'system_number', - 'status', 'region', 'issue_date', 'notes') - } + "fields": ( + "visual_number", + "system_number", + "status", + "region", + "issue_date", + "notes", + ) + }, ), ( - _('User Info'), - { - 'fields': ('user', 'owner', 'get_employee_id', - 'get_employee_company') - } + _("User Info"), + {"fields": ("user", "owner", "get_employee_id", "get_employee_company")}, ), - ( - _('Access Zones'), - { - 'fields': ('access_zones',) - } - ), - + (_("Access Zones"), {"fields": ("access_zones",)}), ) def get_employee_id(self, obj): if obj.user is not None: return obj.user.employee_id else: - return '-' + return "-" - get_employee_id.short_description = _('Employee ID') + get_employee_id.short_description = _("Employee ID") def get_employee_company(self, obj): if obj.user is not None: return obj.user.company else: - return '-' + return "-" - get_employee_company.short_description = _('Employee Company') + get_employee_company.short_description = _("Employee Company") @register(AccessZone) class AccessZoneAdmin(RalphMPTTAdmin): - list_display = ['name', 'parent', 'description'] - search_fields = ['name', 'description'] + list_display = ["name", "parent", "description"] + search_fields = ["name", "description"] - fieldsets = ( - ( - _('Access Zone'), - { - 'fields': ('parent', 'name', 'description') - } - ), - ) + fieldsets = ((_("Access Zone"), {"fields": ("parent", "name", "description")}),) diff --git a/src/ralph/access_cards/api.py b/src/ralph/access_cards/api.py index acc2707bd0..ff49247572 100644 --- a/src/ralph/access_cards/api.py +++ b/src/ralph/access_cards/api.py @@ -7,7 +7,7 @@ class AccessZoneSimpleSerializer(RalphAPISerializer): class Meta: model = AccessZone depth = 0 - fields = ['id', 'name', 'parent', 'description'] + fields = ["id", "name", "parent", "description"] class AccessZoneSerializer(RalphAPISerializer): @@ -25,19 +25,30 @@ class AccessCardSerializer(RalphAPISerializer): class Meta: model = AccessCard - fields = ['id', 'status', 'user', 'owner', 'created', 'modified', - 'visual_number', 'system_number', 'issue_date', 'notes', - 'region', 'access_zones'] + fields = [ + "id", + "status", + "user", + "owner", + "created", + "modified", + "visual_number", + "system_number", + "issue_date", + "notes", + "region", + "access_zones", + ] class AccessCardViewSet(RalphAPIViewSet): - queryset = AccessCard.objects.order_by('id').all() - select_related = ['user', 'owner', 'region'] + queryset = AccessCard.objects.order_by("id").all() + select_related = ["user", "owner", "region"] serializer_class = AccessCardSerializer - prefetch_related = ['access_zones'] + prefetch_related = ["access_zones"] extended_filter_fields = { - 'access_zones__name': ['access_zones__name__icontains'], - 'access_zones__id': ['access_zones__id'] + "access_zones__name": ["access_zones__name__icontains"], + "access_zones__id": ["access_zones__id"], } @@ -46,6 +57,6 @@ class AccessZoneViewSet(RalphAPIViewSet): serializer_class = AccessZoneSerializer -router.register(r'access-card', AccessCardViewSet) -router.register(r'access-zone', AccessZoneViewSet) +router.register(r"access-card", AccessCardViewSet) +router.register(r"access-zone", AccessZoneViewSet) urlpatterns = [] diff --git a/src/ralph/access_cards/migrations/0001_initial.py b/src/ralph/access_cards/migrations/0001_initial.py index 9a3ab831d8..d18a0a2d99 100644 --- a/src/ralph/access_cards/migrations/0001_initial.py +++ b/src/ralph/access_cards/migrations/0001_initial.py @@ -10,31 +10,101 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0006_remove_ralphuser_gender'), + ("accounts", "0006_remove_ralphuser_gender"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='AccessCard', + name="AccessCard", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('visual_number', models.CharField(max_length=255, unique=True, help_text='Number visible on the access card')), - ('system_number', models.CharField(max_length=255, unique=True, help_text='Internal number in the access system')), - ('issue_date', models.DateField(blank=True, null=True, help_text='Date of issue to the User')), - ('notes', models.TextField(blank=True, null=True, help_text='Optional notes')), - ('status', dj.choices.fields.ChoiceField(default=1, choices=ralph.access_cards.models.AccessCardStatus, help_text='Access card status')), - ('owner', models.ForeignKey(blank=True, null=True, help_text='Owner of the card', related_name='+', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('region', models.ForeignKey(to='accounts.Region', on_delete=django.db.models.deletion.CASCADE)), - ('user', models.ForeignKey(blank=True, null=True, help_text='User of the card', related_name='+', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "visual_number", + models.CharField( + max_length=255, + unique=True, + help_text="Number visible on the access card", + ), + ), + ( + "system_number", + models.CharField( + max_length=255, + unique=True, + help_text="Internal number in the access system", + ), + ), + ( + "issue_date", + models.DateField( + blank=True, null=True, help_text="Date of issue to the User" + ), + ), + ( + "notes", + models.TextField(blank=True, null=True, help_text="Optional notes"), + ), + ( + "status", + dj.choices.fields.ChoiceField( + default=1, + choices=ralph.access_cards.models.AccessCardStatus, + help_text="Access card status", + ), + ), + ( + "owner", + models.ForeignKey( + blank=True, + null=True, + help_text="Owner of the card", + related_name="+", + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "region", + models.ForeignKey( + to="accounts.Region", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + help_text="User of the card", + related_name="+", + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ - 'ordering': ('-modified', '-created'), - 'abstract': False, + "ordering": ("-modified", "-created"), + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), diff --git a/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py b/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py index e50285a6b6..d3c5179de9 100644 --- a/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py +++ b/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py @@ -8,36 +8,59 @@ class Migration(migrations.Migration): - dependencies = [ - ('access_cards', '0001_initial'), + ("access_cards", "0001_initial"), ] operations = [ migrations.CreateModel( - name='AccessZone', + name="AccessZone", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('name', models.CharField(verbose_name='name', max_length=255)), - ('description', models.TextField(blank=True, null=True, help_text='Optional description')), - ('lft', models.PositiveIntegerField(db_index=True, editable=False)), - ('rght', models.PositiveIntegerField(db_index=True, editable=False)), - ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), - ('level', models.PositiveIntegerField(db_index=True, editable=False)), - ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, related_name='children', to='access_cards.AccessZone', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ("name", models.CharField(verbose_name="name", max_length=255)), + ( + "description", + models.TextField( + blank=True, null=True, help_text="Optional description" + ), + ), + ("lft", models.PositiveIntegerField(db_index=True, editable=False)), + ("rght", models.PositiveIntegerField(db_index=True, editable=False)), + ("tree_id", models.PositiveIntegerField(db_index=True, editable=False)), + ("level", models.PositiveIntegerField(db_index=True, editable=False)), + ( + "parent", + mptt.fields.TreeForeignKey( + blank=True, + null=True, + related_name="children", + to="access_cards.AccessZone", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'ordering': ['name'], + "ordering": ["name"], }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.AddField( - model_name='accesscard', - name='access_zones', - field=mptt.fields.TreeManyToManyField(blank=True, related_name='access_cards', to='access_cards.AccessZone'), + model_name="accesscard", + name="access_zones", + field=mptt.fields.TreeManyToManyField( + blank=True, related_name="access_cards", to="access_cards.AccessZone" + ), ), migrations.AlterUniqueTogether( - name='accesszone', - unique_together=set([('name', 'parent')]), + name="accesszone", + unique_together=set([("name", "parent")]), ), ] diff --git a/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py b/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py index 75f630c5e2..f37781c373 100644 --- a/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py +++ b/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py @@ -1,20 +1,32 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('access_cards', '0002_auto_20200116_1248'), + ("access_cards", "0002_auto_20200116_1248"), ] operations = [ migrations.AlterField( - model_name='accesscard', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'lost'), (4, 'damaged'), (5, 'in use'), (6, 'free'), (7, 'return in progres'), (8, 'liquidated')], help_text='Access card status'), + model_name="accesscard", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "lost"), + (4, "damaged"), + (5, "in use"), + (6, "free"), + (7, "return in progres"), + (8, "liquidated"), + ], + help_text="Access card status", + ), ), ] diff --git a/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py b/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py index e5ac472737..dd90e5aaf3 100644 --- a/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py +++ b/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py @@ -1,20 +1,33 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('access_cards', '0003_auto_20200121_1354'), + ("access_cards", "0003_auto_20200121_1354"), ] operations = [ migrations.AlterField( - model_name='accesscard', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'lost'), (4, 'damaged'), (5, 'in use'), (6, 'free'), (7, 'return in progress'), (8, 'liquidated'), (9, 'reserved')], help_text='Access card status'), + model_name="accesscard", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "lost"), + (4, "damaged"), + (5, "in use"), + (6, "free"), + (7, "return in progress"), + (8, "liquidated"), + (9, "reserved"), + ], + help_text="Access card status", + ), ), ] diff --git a/src/ralph/access_cards/migrations/0005_auto_20211022_1038.py b/src/ralph/access_cards/migrations/0005_auto_20211022_1038.py index 4123bac3e7..d642d29362 100644 --- a/src/ralph/access_cards/migrations/0005_auto_20211022_1038.py +++ b/src/ralph/access_cards/migrations/0005_auto_20211022_1038.py @@ -7,11 +7,8 @@ class Migration(migrations.Migration): - dependencies = [ - ('access_cards', '0004_auto_20200513_1014'), + ("access_cards", "0004_auto_20200513_1014"), ] - operations = [ - TransitionActionMigration() - ] + operations = [TransitionActionMigration()] diff --git a/src/ralph/access_cards/migrations/0006_auto_20240621_1200.py b/src/ralph/access_cards/migrations/0006_auto_20240621_1200.py index d3a098369d..9f48cd694e 100644 --- a/src/ralph/access_cards/migrations/0006_auto_20240621_1200.py +++ b/src/ralph/access_cards/migrations/0006_auto_20240621_1200.py @@ -6,25 +6,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('access_cards', '0005_auto_20211022_1038'), + ("access_cards", "0005_auto_20211022_1038"), ] operations = [ migrations.AlterField( - model_name='accesszone', - name='level', + model_name="accesszone", + name="level", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='accesszone', - name='lft', + model_name="accesszone", + name="lft", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='accesszone', - name='rght', + model_name="accesszone", + name="rght", field=models.PositiveIntegerField(editable=False), ), ] diff --git a/src/ralph/access_cards/models.py b/src/ralph/access_cards/models.py index 726b3c55f2..af137c4cd0 100644 --- a/src/ralph/access_cards/models.py +++ b/src/ralph/access_cards/models.py @@ -24,39 +24,37 @@ class AccessCardStatus(Choices): _ = Choices.Choice - new = _('new') - in_progress = _('in progress') - lost = _('lost') - damaged = _('damaged') - used = _('in use') - free = _('free') - return_in_progress = _('return in progress') - liquidated = _('liquidated') + new = _("new") + in_progress = _("in progress") + lost = _("lost") + damaged = _("damaged") + used = _("in use") + free = _("free") + return_in_progress = _("return in progress") + liquidated = _("liquidated") reserved = _("reserved") class AccessZone(AdminAbsoluteUrlMixin, MPTTModel, models.Model): - name = models.CharField(_('name'), max_length=255) + name = models.CharField(_("name"), max_length=255) class Meta: - ordering = ['name'] - unique_together = ['name', 'parent'] + ordering = ["name"] + unique_together = ["name", "parent"] def __str__(self): return self.name description = models.TextField( - null=True, - blank=True, - help_text=_('Optional description') + null=True, blank=True, help_text=_("Optional description") ) parent = TreeForeignKey( - 'self', + "self", null=True, blank=True, - related_name='children', + related_name="children", db_index=True, - on_delete=models.CASCADE + on_delete=models.CASCADE, ) @@ -65,107 +63,95 @@ class AccessCard( TimeStampMixin, Regionalizable, models.Model, - metaclass=TransitionWorkflowBaseWithPermissions + metaclass=TransitionWorkflowBaseWithPermissions, ): visual_number = models.CharField( max_length=255, null=False, blank=False, unique=True, - help_text=_('Number visible on the access card') + help_text=_("Number visible on the access card"), ) system_number = models.CharField( max_length=255, null=False, blank=False, unique=True, - help_text=_('Internal number in the access system') + help_text=_("Internal number in the access system"), ) issue_date = models.DateField( - null=True, - blank=True, - help_text=_('Date of issue to the User') - ) - notes = models.TextField( - null=True, - blank=True, - help_text=_('Optional notes') + null=True, blank=True, help_text=_("Date of issue to the User") ) + notes = models.TextField(null=True, blank=True, help_text=_("Optional notes")) user = models.ForeignKey( RalphUser, null=True, blank=True, - related_name='+', - help_text=_('User of the card'), - on_delete=models.SET_NULL + related_name="+", + help_text=_("User of the card"), + on_delete=models.SET_NULL, ) owner = models.ForeignKey( RalphUser, null=True, blank=True, - related_name='+', - help_text=('Owner of the card'), - on_delete=models.SET_NULL + related_name="+", + help_text=("Owner of the card"), + on_delete=models.SET_NULL, ) status = TransitionField( choices=AccessCardStatus(), default=AccessCardStatus.new.id, null=False, blank=False, - help_text=_('Access card status') + help_text=_("Access card status"), ) access_zones = TreeManyToManyField( - AccessZone, - blank=True, - related_name='access_cards' + AccessZone, blank=True, related_name="access_cards" ) def __str__(self): - return _('Access Card: {}').format(self.visual_number) + return _("Access Card: {}").format(self.visual_number) @classmethod def get_autocomplete_queryset(cls): - return cls._default_manager.exclude( - status=AccessCardStatus.liquidated.id - ) + return cls._default_manager.exclude(status=AccessCardStatus.liquidated.id) @classmethod @transition_action() def unassign_user(cls, instances, **kwargs): for instance in instances: - kwargs['history_kwargs'][instance.pk][ - 'affected_user' - ] = str(instance.user) + kwargs["history_kwargs"][instance.pk]["affected_user"] = str(instance.user) instance.user = None @classmethod @transition_action( form_fields={ - 'user': { - 'field': forms.CharField(label=_('User')), - 'autocomplete_field': 'user', - 'default_value': partial(autocomplete_user, field_name='user') + "user": { + "field": forms.CharField(label=_("User")), + "autocomplete_field": "user", + "default_value": partial(autocomplete_user, field_name="user"), } }, ) def assign_user(cls, instances, **kwargs): - user = get_user_model().objects.get(pk=int(kwargs['user'])) + user = get_user_model().objects.get(pk=int(kwargs["user"])) for instance in instances: instance.user = user @classmethod @transition_action( form_fields={ - 'owner': { - 'field': forms.CharField(label=_('Owner')), - 'autocomplete_field': 'owner', - 'default_value': partial(autocomplete_user, field_name='owner') + "owner": { + "field": forms.CharField(label=_("Owner")), + "autocomplete_field": "owner", + "default_value": partial(autocomplete_user, field_name="owner"), } }, - help_text=_('assign owner'), + help_text=_("assign owner"), ) def assign_owner(cls, instances, **kwargs): - owner = get_user_model().objects.get(pk=int(kwargs['owner'])) + owner = get_user_model().objects.get(pk=int(kwargs["owner"])) for instance in instances: instance.owner = owner @@ -173,9 +159,9 @@ def assign_owner(cls, instances, **kwargs): @transition_action() def unassign_owner(cls, instances, **kwargs): for instance in instances: - kwargs['history_kwargs'][instance.pk][ - 'affected_owner' - ] = str(instance.owner) + kwargs["history_kwargs"][instance.pk]["affected_owner"] = str( + instance.owner + ) instance.owner = None @classmethod @@ -187,21 +173,17 @@ def clear_access_zones(cls, instances, requester, **kwargs): @classmethod @transition_action( form_fields={ - 'notes': { - 'field': forms.CharField(label=_('notes')), + "notes": { + "field": forms.CharField(label=_("notes")), } } ) def add_notes(cls, instances, **kwargs): for instance in instances: - instance.notes = '{}\n{}'.format( - instance.notes, kwargs['notes'] - ) + instance.notes = "{}\n{}".format(instance.notes, kwargs["notes"]) @classmethod - @transition_action( - run_after=['release_report'] - ) + @transition_action(run_after=["release_report"]) def assign_requester_as_an_owner(cls, instances, requester, **kwargs): """Assign current user as an owner""" for instance in instances: @@ -211,11 +193,10 @@ def assign_requester_as_an_owner(cls, instances, requester, **kwargs): @classmethod @transition_action( form_fields={ - 'accept': { - 'field': forms.BooleanField( + "accept": { + "field": forms.BooleanField( label=_( - 'I have read and fully understand and ' - 'accept the agreement.' + "I have read and fully understand and " "accept the agreement." ) ) }, @@ -227,46 +208,44 @@ def accept_asset_release_agreement(cls, instances, requester, **kwargs): @classmethod @transition_action( form_fields={ - 'report_language': { - 'field': forms.ModelChoiceField( - label=_('Release report language'), - queryset=ReportLanguage.objects.all().order_by('-default'), - empty_label=None + "report_language": { + "field": forms.ModelChoiceField( + label=_("Release report language"), + queryset=ReportLanguage.objects.all().order_by("-default"), + empty_label=None, ), - 'exclude_from_history': True + "exclude_from_history": True, } }, return_attachment=True, - run_after=['assign_owner', 'assign_user'] + run_after=["assign_owner", "assign_user"], ) def release_report(cls, instances, requester, transition_id, **kwargs): report_name = get_report_name_for_transition_id(transition_id) return generate_report( - instances=instances, name=report_name, requester=requester, - language=kwargs['report_language'], - context=cls._get_report_context(instances) + instances=instances, + name=report_name, + requester=requester, + language=kwargs["report_language"], + context=cls._get_report_context(instances), ) @classmethod - @transition_action(run_after=['release_report']) - def send_attachments_to_user( - cls, requester, transition_id, **kwargs - ): - context_func = get_hook( - 'back_office.transition_action.email_context' - ) + @transition_action(run_after=["release_report"]) + def send_attachments_to_user(cls, requester, transition_id, **kwargs): + context_func = get_hook("back_office.transition_action.email_context") send_transition_attachments_to_user( requester=requester, transition_id=transition_id, context_func=context_func, - **kwargs + **kwargs, ) @classmethod def _get_report_context(cls, instances): context = [ { - 'visual_number': obj.visual_number, + "visual_number": obj.visual_number, } for obj in instances ] diff --git a/src/ralph/access_cards/tests/factories.py b/src/ralph/access_cards/tests/factories.py index 77101c2f18..9e935a179b 100644 --- a/src/ralph/access_cards/tests/factories.py +++ b/src/ralph/access_cards/tests/factories.py @@ -6,19 +6,19 @@ class AccessCardFactory(DjangoModelFactory): - visual_number = factory.Sequence(lambda n: '000000000000{}'.format(n)) - system_number = factory.Sequence(lambda n: '000000000000{}'.format(n)) + visual_number = factory.Sequence(lambda n: "000000000000{}".format(n)) + system_number = factory.Sequence(lambda n: "000000000000{}".format(n)) region = factory.SubFactory(RegionFactory) status = AccessCardStatus.new class Meta: model = AccessCard - django_get_or_create = ['visual_number', 'system_number'] + django_get_or_create = ["visual_number", "system_number"] class AccessZoneFactory(DjangoModelFactory): - name = factory.sequence(lambda n: 'Zone {}'.format(n)) + name = factory.sequence(lambda n: "Zone {}".format(n)) class Meta: model = AccessZone - django_get_or_create = ['name'] + django_get_or_create = ["name"] diff --git a/src/ralph/access_cards/tests/test_api.py b/src/ralph/access_cards/tests/test_api.py index 0fc7908f9c..4906f5ec81 100644 --- a/src/ralph/access_cards/tests/test_api.py +++ b/src/ralph/access_cards/tests/test_api.py @@ -3,54 +3,31 @@ from rest_framework import status from rest_framework.reverse import reverse -from ralph.access_cards.tests.factories import ( - AccessCardFactory, - AccessZoneFactory -) +from ralph.access_cards.tests.factories import AccessCardFactory, AccessZoneFactory from ralph.accounts.tests.factories import RegionFactory from ralph.api.tests._base import RalphAPITestCase from ralph.tests.factories import UserFactory class AccessCardTestCase(RalphAPITestCase): - def assertAccessCardHasCertainFieldsAndValues( - self, access_card, response_data - ): - self.assertEqual(response_data['status'], access_card.status.name) + def assertAccessCardHasCertainFieldsAndValues(self, access_card, response_data): + self.assertEqual(response_data["status"], access_card.status.name) + self.assertEqual(response_data["system_number"], access_card.system_number) + self.assertEqual(response_data["visual_number"], access_card.visual_number) self.assertEqual( - response_data['system_number'], - access_card.system_number - ) - self.assertEqual( - response_data['visual_number'], - access_card.visual_number - ) - self.assertEqual( - response_data['issue_date'], - access_card.issue_date.strftime('%Y-%m-%d') - ) - self.assertEqual(response_data['notes'], access_card.notes) - self.assertEqual( - response_data['user']['username'], - access_card.user.username - ) - self.assertEqual( - response_data['owner']['username'], - access_card.owner.username - ) - self.assertEqual( - response_data['region']['id'], - access_card.region.id + response_data["issue_date"], access_card.issue_date.strftime("%Y-%m-%d") ) + self.assertEqual(response_data["notes"], access_card.notes) + self.assertEqual(response_data["user"]["username"], access_card.user.username) + self.assertEqual(response_data["owner"]["username"], access_card.owner.username) + self.assertEqual(response_data["region"]["id"], access_card.region.id) access_zone_ids = [ - access_zone['id'] - for access_zone in response_data['access_zones'] + access_zone["id"] for access_zone in response_data["access_zones"] ] access_zone_ids.sort() self.assertEqual( - access_zone_ids, - list(access_card.access_zones.values_list('id', flat=True)) + access_zone_ids, list(access_card.access_zones.values_list("id", flat=True)) ) def test_detail_access_card_returns_expected_fields(self): @@ -58,52 +35,48 @@ def test_detail_access_card_returns_expected_fields(self): issue_date=datetime.now(), user=UserFactory(), owner=UserFactory(), - notes='test' + notes="test", ) access_card.access_zones.add(AccessZoneFactory()) access_card.save() - url = reverse('accesscard-detail', args=(access_card.id,)) + url = reverse("accesscard-detail", args=(access_card.id,)) response = self.client.get(url) self.assertEqual(status.HTTP_200_OK, response.status_code) - self.assertAccessCardHasCertainFieldsAndValues( - access_card, response.data - ) + self.assertAccessCardHasCertainFieldsAndValues(access_card, response.data) def test_list_access_card_returns_expected_fields(self): access_card1 = AccessCardFactory( issue_date=datetime.now(), user=UserFactory(), owner=UserFactory(), - notes='test' + notes="test", ) access_card2 = AccessCardFactory( issue_date=datetime.now(), user=UserFactory(), owner=UserFactory(), - notes='test' + notes="test", ) - url = reverse('accesscard-list') + url = reverse("accesscard-list") response = self.client.get(url) self.assertEqual(status.HTTP_200_OK, response.status_code) self.assertAccessCardHasCertainFieldsAndValues( - access_card1, response.data['results'][0] + access_card1, response.data["results"][0] ) self.assertAccessCardHasCertainFieldsAndValues( - access_card2, response.data['results'][1] + access_card2, response.data["results"][1] ) def test_filter_access_card_by_access_zone_name(self): zones = [AccessZoneFactory() for _ in range(2)] cards = [ AccessCardFactory( - issue_date=datetime.now(), - user=UserFactory(), - owner=UserFactory() + issue_date=datetime.now(), user=UserFactory(), owner=UserFactory() ) for _ in range(10) ] @@ -115,31 +88,30 @@ def test_filter_access_card_by_access_zone_name(self): card.access_zones.add(zones[1]) card.save() - url = reverse('accesscard-list') + '?access_zones__name={}'.format( + url = reverse("accesscard-list") + "?access_zones__name={}".format( zones[0].name ) response = self.client.get(url) self.assertEqual(status.HTTP_200_OK, response.status_code) - self.assertEqual(1, response.data['count']) + self.assertEqual(1, response.data["count"]) self.assertAccessCardHasCertainFieldsAndValues( - cards[0], - response.data['results'][0] + cards[0], response.data["results"][0] ) def test_class_access_card_test_case(self): region = RegionFactory() access_card = { - 'status': "in use", - 'visual_number': '654321', - 'system_number': 'F9876DSGV', - 'notes': 'test note', - 'issue_date': '2020-01-02', - 'region': region.id + "status": "in use", + "visual_number": "654321", + "system_number": "F9876DSGV", + "notes": "test note", + "issue_date": "2020-01-02", + "region": region.id, } - url = reverse('accesscard-list') + url = reverse("accesscard-list") response = self.client.post(url, data=access_card) self.assertEqual(status.HTTP_201_CREATED, response.status_code) diff --git a/src/ralph/accessories/admin.py b/src/ralph/accessories/admin.py index f7c32eb480..0647dd9b53 100644 --- a/src/ralph/accessories/admin.py +++ b/src/ralph/accessories/admin.py @@ -8,14 +8,14 @@ class AccessoryUserView(RalphDetailViewAdmin): - icon = 'user' - name = 'users' - label = _('Assigned to users') - url_name = 'assigned-to-users' + icon = "user" + name = "users" + label = _("Assigned to users") + url_name = "assigned-to-users" class AccessoryUserInline(RalphTabularInline): model = AccessoryUser - raw_id_fields = ('user',) + raw_id_fields = ("user",) extra = 1 inlines = [AccessoryUserInline] @@ -24,30 +24,45 @@ class AccessoryUserInline(RalphTabularInline): @register(Accessory) class AccessoryAdmin(TransitionAdminMixin, RalphAdmin): show_transition_history = True - list_display = ['status', 'manufacturer', 'accessory_name', - 'product_number', 'number_bought', 'free'] - readonly_fields = ['used', 'free'] - list_select_related = ['owner'] - raw_id_fields = ['owner', 'region'] - list_filter = ['status', 'manufacturer', 'accessory_name', - 'product_number', 'warehouse'] - change_views = [AccessoryUserView, ] - search_fields = ['accessory_name', 'product_number'] + list_display = [ + "status", + "manufacturer", + "accessory_name", + "product_number", + "number_bought", + "free", + ] + readonly_fields = ["used", "free"] + list_select_related = ["owner"] + raw_id_fields = ["owner", "region"] + list_filter = [ + "status", + "manufacturer", + "accessory_name", + "product_number", + "warehouse", + ] + change_views = [ + AccessoryUserView, + ] + search_fields = ["accessory_name", "product_number"] fieldsets = ( ( - _('Accessory Info'), + _("Accessory Info"), { - 'fields': ('manufacturer', 'accessory_name', - 'category', 'product_number', - 'region', 'warehouse', 'number_bought', - 'used', 'free',) - } - ), - ( - _('User Info'), - { - 'fields': ('owner', ) - } + "fields": ( + "manufacturer", + "accessory_name", + "category", + "product_number", + "region", + "warehouse", + "number_bought", + "used", + "free", + ) + }, ), + (_("User Info"), {"fields": ("owner",)}), ) diff --git a/src/ralph/accessories/migrations/0001_initial.py b/src/ralph/accessories/migrations/0001_initial.py index 9a8966f0ad..0cd7ef0652 100644 --- a/src/ralph/accessories/migrations/0001_initial.py +++ b/src/ralph/accessories/migrations/0001_initial.py @@ -9,56 +9,152 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('back_office', '0011_auto_20190517_1115'), - ('accounts', '0006_remove_ralphuser_gender'), + ("back_office", "0011_auto_20190517_1115"), + ("accounts", "0006_remove_ralphuser_gender"), ] operations = [ migrations.CreateModel( - name='Accessory', + name="Accessory", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('manufacturer', models.CharField(max_length=255, help_text='Accessory manufacturer')), - ('accessory_type', models.CharField(max_length=255, help_text='Accessory type')), - ('accessory_name', models.CharField(max_length=255, unique=True, help_text='Accessory name')), - ('product_number', models.CharField(max_length=255, unique=True, help_text='Number of accessories')), - ('status', ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'lost'), (4, 'damaged'), (5, 'in use'), (6, 'free'), (7, 'return in progress'), (8, 'liquidated'), (9, 'reserved')], help_text='Accessory status')), - ('number_bought', models.IntegerField(verbose_name='number of purchased items')), - ('owner', models.ForeignKey(blank=True, null=True, help_text='Accessory owner', related_name='+', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('region', models.ForeignKey(to='accounts.Region', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "manufacturer", + models.CharField( + max_length=255, help_text="Accessory manufacturer" + ), + ), + ( + "accessory_type", + models.CharField(max_length=255, help_text="Accessory type"), + ), + ( + "accessory_name", + models.CharField( + max_length=255, unique=True, help_text="Accessory name" + ), + ), + ( + "product_number", + models.CharField( + max_length=255, unique=True, help_text="Number of accessories" + ), + ), + ( + "status", + ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "lost"), + (4, "damaged"), + (5, "in use"), + (6, "free"), + (7, "return in progress"), + (8, "liquidated"), + (9, "reserved"), + ], + help_text="Accessory status", + ), + ), + ( + "number_bought", + models.IntegerField(verbose_name="number of purchased items"), + ), + ( + "owner", + models.ForeignKey( + blank=True, + null=True, + help_text="Accessory owner", + related_name="+", + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "region", + models.ForeignKey( + to="accounts.Region", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'ordering': ('-modified', '-created'), - 'abstract': False, + "ordering": ("-modified", "-created"), + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='AccessoryUser', + name="AccessoryUser", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('quantity', models.PositiveIntegerField(default=1)), - ('accessory', models.ForeignKey(to='accessories.Accessory', on_delete=django.db.models.deletion.CASCADE)), - ('user', models.ForeignKey(related_name='user', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ("quantity", models.PositiveIntegerField(default=1)), + ( + "accessory", + models.ForeignKey( + to="accessories.Accessory", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "user", + models.ForeignKey( + related_name="user", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], ), migrations.AddField( - model_name='accessory', - name='user', - field=models.ManyToManyField(related_name='_accessory_user_+', to=settings.AUTH_USER_MODEL, through='accessories.AccessoryUser'), + model_name="accessory", + name="user", + field=models.ManyToManyField( + related_name="_accessory_user_+", + to=settings.AUTH_USER_MODEL, + through="accessories.AccessoryUser", + ), ), migrations.AddField( - model_name='accessory', - name='warehouse', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='back_office.Warehouse'), + model_name="accessory", + name="warehouse", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="back_office.Warehouse" + ), ), migrations.AlterUniqueTogether( - name='accessoryuser', - unique_together=set([('accessory', 'user')]), + name="accessoryuser", + unique_together=set([("accessory", "user")]), ), ] diff --git a/src/ralph/accessories/migrations/0002_auto_20210510_1246.py b/src/ralph/accessories/migrations/0002_auto_20210510_1246.py index 3783f53b2a..fd870bd376 100644 --- a/src/ralph/accessories/migrations/0002_auto_20210510_1246.py +++ b/src/ralph/accessories/migrations/0002_auto_20210510_1246.py @@ -7,31 +7,35 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0032_auto_20200909_1012'), - ('accessories', '0001_initial'), + ("assets", "0032_auto_20200909_1012"), + ("accessories", "0001_initial"), ] operations = [ migrations.RemoveField( - model_name='accessory', - name='accessory_type', + model_name="accessory", + name="accessory_type", ), migrations.AddField( - model_name='accessory', - name='category', - field=mptt.fields.TreeForeignKey(null=True, related_name='+', to='assets.Category', on_delete=django.db.models.deletion.CASCADE), - ), - migrations.RemoveField( - model_name='accessory', - name='manufacturer' + model_name="accessory", + name="category", + field=mptt.fields.TreeForeignKey( + null=True, + related_name="+", + to="assets.Category", + on_delete=django.db.models.deletion.CASCADE, + ), ), + migrations.RemoveField(model_name="accessory", name="manufacturer"), migrations.AddField( - model_name='accessory', - name='manufacturer', - field=models.ForeignKey(blank=True, null=True, - on_delete=django.db.models.deletion.PROTECT, - to='assets.Manufacturer'), + model_name="accessory", + name="manufacturer", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="assets.Manufacturer", + ), ), ] diff --git a/src/ralph/accessories/migrations/0003_auto_20210607_1226.py b/src/ralph/accessories/migrations/0003_auto_20210607_1226.py index 6b8f7018d4..71de4cd394 100644 --- a/src/ralph/accessories/migrations/0003_auto_20210607_1226.py +++ b/src/ralph/accessories/migrations/0003_auto_20210607_1226.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('accessories', '0002_auto_20210510_1246'), + ("accessories", "0002_auto_20210510_1246"), ] operations = [ migrations.AlterField( - model_name='accessory', - name='accessory_name', - field=models.CharField(max_length=255, help_text='Accessory name'), + model_name="accessory", + name="accessory_name", + field=models.CharField(max_length=255, help_text="Accessory name"), ), ] diff --git a/src/ralph/accessories/models.py b/src/ralph/accessories/models.py index 46d4e681a2..eaa55ce589 100644 --- a/src/ralph/accessories/models.py +++ b/src/ralph/accessories/models.py @@ -30,8 +30,8 @@ class AccessoryUsedFreeManager(models.Manager): def get_queryset(self): id_column = Accessory.baseobject_ptr.field.column - user_quantity_field = Accessory.users.through._meta.get_field('quantity') # noqa - user_accessory_field = Accessory.users.through._meta.get_field('accessory') # noqa + user_quantity_field = Accessory.users.through._meta.get_field("quantity") # noqa + user_accessory_field = Accessory.users.through._meta.get_field("accessory") # noqa user_count_query = _SELECT_USED_ACCESSORY_QUERY.format( assignment_table=Accessory.users.through._meta.db_table, quantity_column=user_quantity_field.db_column or user_quantity_field.column, # noqa @@ -40,30 +40,32 @@ def get_queryset(self): id_column=id_column, ) - return super().get_queryset().extra( - select={ - 'user_count': user_count_query, - } + return ( + super() + .get_queryset() + .extra( + select={ + "user_count": user_count_query, + } + ) ) -class AccessoryUsedFreeRelatedObjectsManager( - AccessoryUsedFreeManager -): +class AccessoryUsedFreeRelatedObjectsManager(AccessoryUsedFreeManager): pass class AccessoryStatus(Choices): _ = Choices.Choice - new = _('new') - in_progress = _('in progress') - lost = _('lost') - damaged = _('damaged') - used = _('in use') - free = _('free') - return_in_progress = _('return in progress') - liquidated = _('liquidated') + new = _("new") + in_progress = _("in progress") + lost = _("lost") + damaged = _("damaged") + used = _("in use") + free = _("free") + return_in_progress = _("return in progress") + liquidated = _("liquidated") reserved = _("reserved") @@ -72,101 +74,93 @@ class Accessory( TimeStampMixin, Regionalizable, models.Model, - metaclass=TransitionWorkflowBaseWithPermissions + metaclass=TransitionWorkflowBaseWithPermissions, ): manufacturer = models.ForeignKey( Manufacturer, on_delete=models.PROTECT, blank=True, null=True ) category = TreeForeignKey( - Category, null=True, related_name='+', on_delete=models.CASCADE + Category, null=True, related_name="+", on_delete=models.CASCADE ) accessory_name = models.CharField( - max_length=255, - null=False, - blank=False, - help_text=_('Accessory name') + max_length=255, null=False, blank=False, help_text=_("Accessory name") ) product_number = models.CharField( max_length=255, null=False, blank=False, unique=True, - help_text=_('Number of accessories') + help_text=_("Number of accessories"), ) user = models.ManyToManyField( - settings.AUTH_USER_MODEL, - through='AccessoryUser', - related_name='+' + settings.AUTH_USER_MODEL, through="AccessoryUser", related_name="+" ) owner = models.ForeignKey( RalphUser, null=True, blank=True, - related_name='+', - help_text=_('Accessory owner'), - on_delete=models.SET_NULL + related_name="+", + help_text=_("Accessory owner"), + on_delete=models.SET_NULL, ) status = TransitionField( choices=AccessoryStatus(), default=AccessoryStatus.new.id, null=False, blank=False, - help_text=_('Accessory status') - ) - number_bought = models.IntegerField( - verbose_name=_('number of purchased items') - ) - warehouse = models.ForeignKey( - Warehouse, - on_delete=models.PROTECT + help_text=_("Accessory status"), ) + number_bought = models.IntegerField(verbose_name=_("number of purchased items")) + warehouse = models.ForeignKey(Warehouse, on_delete=models.PROTECT) objects = models.Manager() @classmethod @transition_action( form_fields={ - 'restock': { - 'field': forms.IntegerField(label=_('restock'),) + "restock": { + "field": forms.IntegerField( + label=_("restock"), + ) } }, ) def restock(cls, instances, **kwargs): - restock = int(kwargs['restock']) + restock = int(kwargs["restock"]) for instance in instances: instance.number_bought += restock @classmethod @transition_action( form_fields={ - 'accessory_send': { - 'field': forms.IntegerField(label=_('accessory_send'),) + "accessory_send": { + "field": forms.IntegerField( + label=_("accessory_send"), + ) } }, ) def accessory_send(cls, instances, **kwargs): - accessory_send = int(kwargs['accessory_send']) + accessory_send = int(kwargs["accessory_send"]) for instance in instances: instance.number_bought -= accessory_send @classmethod @transition_action( form_fields={ - 'user': { - 'field': forms.CharField(label=_('User')), - 'autocomplete_field': 'user', + "user": { + "field": forms.CharField(label=_("User")), + "autocomplete_field": "user", + }, + "quantity": { + "field": forms.IntegerField(label=_("Quantity")), }, - 'quantity': { - 'field': forms.IntegerField(label=_('Quantity')), - } }, ) def release_accessories(cls, instances, **kwargs): - user = get_user_model().objects.get(pk=int(kwargs['user'])) - quantity = kwargs['quantity'] + user = get_user_model().objects.get(pk=int(kwargs["user"])) + quantity = kwargs["quantity"] accessory_user, created = AccessoryUser.objects.get_or_create( - user=user, - accessory=instances[0], - defaults={'quantity': quantity} + user=user, accessory=instances[0], defaults={"quantity": quantity} ) if not created: accessory_user.quantity += quantity @@ -197,37 +191,40 @@ def used(self): if not self.pk: return 0 try: - return (self.user_count or 0) + return self.user_count or 0 except AttributeError: users_qs = self.user.through.objects.filter(accessory=self) def get_sum(qs): - return qs.aggregate(sum=Sum('quantity'))['sum'] or 0 + return qs.aggregate(sum=Sum("quantity"))["sum"] or 0 + return sum(map(get_sum, [users_qs])) - used._permission_field = 'number_bought' + + used._permission_field = "number_bought" @cached_property def free(self): if not self.pk: return 0 return self.number_bought - self.used - free._permission_field = 'number_bought' + + free._permission_field = "number_bought" @reversion.register() class AccessoryUser(models.Model): accessory = models.ForeignKey(Accessory, on_delete=models.CASCADE) user = models.ForeignKey( - settings.AUTH_USER_MODEL, - related_name='user', - on_delete=models.CASCADE + settings.AUTH_USER_MODEL, related_name="user", on_delete=models.CASCADE ) quantity = models.PositiveIntegerField(default=1) class Meta: - unique_together = ('accessory', 'user') + unique_together = ("accessory", "user") def __str__(self): - return '{} of {} assigned to {}'.format( - self.quantity, self.accessory, self.user, + return "{} of {} assigned to {}".format( + self.quantity, + self.accessory, + self.user, ) diff --git a/src/ralph/accessories/tests/factories.py b/src/ralph/accessories/tests/factories.py index cc215dacbd..81fe925c2f 100644 --- a/src/ralph/accessories/tests/factories.py +++ b/src/ralph/accessories/tests/factories.py @@ -10,8 +10,8 @@ class AccessoryFactory(DjangoModelFactory): manufacturer = SubFactory(ManufacturerFactory) category = SubFactory(CategoryFactory) - accessory_name = Sequence(lambda n: 'Accessory {}'.format(n)) - product_number = Sequence(lambda n: 'Product number {}'.format(n)) + accessory_name = Sequence(lambda n: "Accessory {}".format(n)) + product_number = Sequence(lambda n: "Product number {}".format(n)) owner = SubFactory(UserFactory) status = AccessoryStatus.new number_bought = 1 diff --git a/src/ralph/accounts/__init__.py b/src/ralph/accounts/__init__.py index 3b4d931b0d..253a783399 100644 --- a/src/ralph/accounts/__init__.py +++ b/src/ralph/accounts/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.accounts.apps.AccountsConfig' +default_app_config = "ralph.accounts.apps.AccountsConfig" diff --git a/src/ralph/accounts/admin.py b/src/ralph/accounts/admin.py index 4192b8ffba..1015218fd3 100644 --- a/src/ralph/accounts/admin.py +++ b/src/ralph/accounts/admin.py @@ -29,25 +29,25 @@ # use string for whole app (app_label) or tuple (app_label, model_name) to # exclude particular model PERMISSIONS_EXCLUDE = [ - 'admin', - 'attachment', - 'authtoken', - 'contenttypes', - 'data_importer', - 'reversion', - 'sessions', - 'sitetree', - 'taggit', - ('assets', 'assetlasthostname'), - ('transitions', 'action'), - ('transitions', 'transitionshistory'), - ('transitions', 'transitionmodel'), + "admin", + "attachment", + "authtoken", + "contenttypes", + "data_importer", + "reversion", + "sessions", + "sitetree", + "taggit", + ("assets", "assetlasthostname"), + ("transitions", "action"), + ("transitions", "transitionshistory"), + ("transitions", "transitionmodel"), ] def quotation_to_inches(text): """Replace quotation by unicode inches sign.""" - return text.replace('"', '\u2033') + return text.replace('"', "\u2033") class EditPermissionsFormMixin(object): @@ -57,20 +57,19 @@ def _simplify_permissions(self, queryset): Permissions to exclude are defined in PERMISSIONS_EXCLUDE. """ - queryset = queryset.exclude(content_type__app_label__in=[ - ct for ct in PERMISSIONS_EXCLUDE if not isinstance( - ct, (tuple, list) - ) - ]) + queryset = queryset.exclude( + content_type__app_label__in=[ + ct for ct in PERMISSIONS_EXCLUDE if not isinstance(ct, (tuple, list)) + ] + ) for value in PERMISSIONS_EXCLUDE: if isinstance(value, (tuple, list)): app_label, model_name = value queryset = queryset.exclude( - content_type__app_label=app_label, - content_type__model=model_name + content_type__app_label=app_label, content_type__model=model_name ) - queryset = queryset.select_related('content_type').order_by( - 'content_type__model' + queryset = queryset.select_related("content_type").order_by( + "content_type__model" ) return queryset @@ -80,7 +79,7 @@ class RalphUserChangeForm( ): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - field = self.fields.get('user_permissions', None) + field = self.fields.get("user_permissions", None) if field: self._simplify_permissions(field.queryset) @@ -95,70 +94,66 @@ def clean_password(self): class AssetList(Table): - def buyout_date(self, item): if item.status in [ BackOfficeAssetStatus.in_use_team.id, - BackOfficeAssetStatus.in_use_test.id + BackOfficeAssetStatus.in_use_test.id, ]: - return '' + return "" if item.model.category.show_buyout_date: return item.buyout_date - return '—' - buyout_date.title = _('Buyout date') + return "—" + + buyout_date.title = _("Buyout date") def user_licence(self, item): - licences = item.licences.select_related('licence') + licences = item.licences.select_related("licence") if licences: result = [ '{}
'.format( reverse( - 'admin:licences_licence_change', - args=(licence.licence.pk,) + "admin:licences_licence_change", args=(licence.licence.pk,) ), - licence.licence - ) for licence in licences + licence.licence, + ) + for licence in licences ] - return [''.join(result)] + return ["".join(result)] else: return [] def buyout_ticket(self, item): if not item.model.category.show_buyout_date: - return '' + return "" if item.status is not BackOfficeAssetStatus.used.id: - return '' + return "" else: get_params = { "inventory_number": item.barcode, "serial_number": item.sn, "model": quotation_to_inches(str(item.model)), - "comment": item.buyout_date + "comment": item.buyout_date, } - url = "?".join( - [settings.MY_EQUIPMENT_BUYOUT_URL, urlencode(get_params)] - ) - url_title = 'Report buyout' + url = "?".join([settings.MY_EQUIPMENT_BUYOUT_URL, urlencode(get_params)]) + url_title = "Report buyout" return self.create_report_link(url, url_title, item) - buyout_ticket.title = 'buyout_ticket' + + buyout_ticket.title = "buyout_ticket" def report_failure(self, item): url = settings.MY_EQUIPMENT_REPORT_FAILURE_URL - url_title = 'Report failure' + url_title = "Report failure" return self.create_report_link(url, url_title, item) - report_failure.title = '' + + report_failure.title = "" def create_report_link(self, url, url_title, item): item_dict = model_to_dict(item) if url: - placeholders = [ - k[1] for k in Formatter().parse(url) if k[1] is not None - ] - item_dict.update({ - k: getattr_dunder(item, k) for k in placeholders - }) - if self.request and 'username' not in item_dict: - item_dict['username'] = self.request.user.username + placeholders = [k[1] for k in Formatter().parse(url) if k[1] is not None] + item_dict.update({k: getattr_dunder(item, k) for k in placeholders}) + if self.request and "username" not in item_dict: + item_dict["username"] = self.request.user.username def escape_param(p): """ @@ -167,48 +162,36 @@ def escape_param(p): return quote_plus(quotation_to_inches(str(p))) return '{}
'.format( - url.format( - **{k: escape_param(v) for (k, v) in item_dict.items()} - ), - _(url_title) + url.format(**{k: escape_param(v) for (k, v) in item_dict.items()}), + _(url_title), ) - return '' + return "" def confirm_ownership(self, item): has_inv_tag = any( [n.startswith(settings.INVENTORY_TAG) for n in item.tags.names()] ) - if not ( - item.warehouse.stocktaking_enabled or - item.region.stocktaking_enabled - ): - return '' + if not (item.warehouse.stocktaking_enabled or item.region.stocktaking_enabled): + return "" elif settings.INVENTORY_TAG_MISSING in item.tags.names(): - return _( - '
missing
' - ) + return _('
missing
') elif has_inv_tag: - return _( - '
confirmed
' - ) + return _('
confirmed
') elif item.user == self.request.user: - return '{}' \ - '' \ - '{}'.format( - reverse( - 'inventory_tag_confirmation', - args=[item.id, 'yes'] - ), - _('yes'), - reverse( - 'inventory_tag_confirmation', - args=[item.id, 'no'] - ), - _('no') - ) + return ( + '{}' + '' + "{}".format( + reverse("inventory_tag_confirmation", args=[item.id, "yes"]), + _("yes"), + reverse("inventory_tag_confirmation", args=[item.id, "no"]), + _("no"), + ) + ) else: - return _('Only asset\'s user can confirm.') - confirm_ownership.title = _('Do you have it?') + return _("Only asset's user can confirm.") + + confirm_ownership.title = _("Do you have it?") class AssignedLicenceList(Table): @@ -224,114 +207,122 @@ class UserInfoMixin(object): def get_user(self): if not self.user: - raise NotImplementedError('Please specify user.') + raise NotImplementedError("Please specify user.") return self.user def get_asset_queryset(self): return BackOfficeAsset.objects.filter( Q(user=self.get_user()) | Q(owner=self.get_user()) - ).select_related('model', 'model__category', 'model__manufacturer') + ).select_related("model", "model__category", "model__manufacturer") def get_licence_queryset(self): - return Licence.objects.filter( - users=self.get_user() - ).select_related('software') + return Licence.objects.filter(users=self.get_user()).select_related("software") def get_simcard_queryset(self): - return SIMCard.objects.filter( - user=self.get_user() - ) + return SIMCard.objects.filter(user=self.get_user()) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # TODO: check permission to field or model - context['asset_list'] = AssetList( + context["asset_list"] = AssetList( self.get_asset_queryset(), [ - 'id', 'model__category__name', 'model__manufacturer__name', - 'model__name', 'sn', 'barcode', 'remarks', 'status', - 'buyout_date', + "id", + "model__category__name", + "model__manufacturer__name", + "model__name", + "sn", + "barcode", + "remarks", + "status", + "buyout_date", ], - ['user_licence'] + ["user_licence"], ) - context['licence_list'] = AssignedLicenceList( + context["licence_list"] = AssignedLicenceList( self.get_licence_queryset(), - ['id', 'manufacturer', 'software__name', - 'licence_type', 'sn', 'valid_thru'] + [ + "id", + "manufacturer", + "software__name", + "licence_type", + "sn", + "valid_thru", + ], ) return context class UserInfoView(UserInfoMixin, RalphDetailView): - icon = 'user' - name = 'user_additional_info' - label = _('Additional info') - url_name = 'user_additional_info' + icon = "user" + name = "user_additional_info" + label = _("Additional info") + url_name = "user_additional_info" def get_user(self): return self.object class UserTransitionHistoryView(RalphDetailView): - icon = 'history' - name = 'user_transition_history' - label = _('Transition history') - url_name = 'user_transition_history' + icon = "history" + name = "user_transition_history" + label = _("Transition history") + url_name = "user_transition_history" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['transitions_history'] = TransitionsHistory.objects.filter( - Q(kwargs__icontains=self.object.username) | - Q(kwargs__icontains=self.object.get_full_name()) + context["transitions_history"] = TransitionsHistory.objects.filter( + Q(kwargs__icontains=self.object.username) + | Q(kwargs__icontains=self.object.get_full_name()) ).distinct() - context['transition_history_in_fieldset'] = False + context["transition_history_in_fieldset"] = False return context @register(RalphUser) class RalphUserAdmin(UserAdmin, RalphAdmin): - form = RalphUserChangeForm - change_views = [ - UserInfoView, - UserTransitionHistoryView - ] - readonly_fields = ('api_token_key',) + change_views = [UserInfoView, UserTransitionHistoryView] + readonly_fields = ("api_token_key",) fieldsets = ( - (None, { - 'fields': ('username',) - }), - (_('Personal info'), { - 'fields': ('first_name', 'last_name', 'email') - }), - (_('Permissions'), { - 'fields': ( - 'is_active', 'is_staff', 'is_superuser', 'groups', - 'user_permissions', 'regions' - ) - }), - (_('Important dates'), { - 'fields': ('last_login', 'date_joined') - }), - (_('Profile'), { - 'fields': ( - 'country', 'city' - ) - }), - (_('Job info'), { - 'fields': ( - 'company', 'profit_center', 'cost_center', 'department', - 'manager', 'location', 'segment', 'team', - ) - }) + (None, {"fields": ("username",)}), + (_("Personal info"), {"fields": ("first_name", "last_name", "email")}), + ( + _("Permissions"), + { + "fields": ( + "is_active", + "is_staff", + "is_superuser", + "groups", + "user_permissions", + "regions", + ) + }, + ), + (_("Important dates"), {"fields": ("last_login", "date_joined")}), + (_("Profile"), {"fields": ("country", "city")}), + ( + _("Job info"), + { + "fields": ( + "company", + "profit_center", + "cost_center", + "department", + "manager", + "location", + "segment", + "team", + ) + }, + ), ) def get_queryset(self, *args, **kwargs): - return super().get_queryset(*args, **kwargs).select_related( - 'auth_token' - ) + return super().get_queryset(*args, **kwargs).select_related("auth_token") - def user_change_password(self, request, id, form_url=''): + def user_change_password(self, request, id, form_url=""): # This is backport of django #29686 ticket # https://code.djangoproject.com/ticket/29686 # Django does not pass user object to has_change_permission method @@ -346,53 +337,57 @@ def user_change_password(self, request, id, form_url=''): @register(Group) class RalphGroupAdmin(EditPermissionsFormMixin, GroupAdmin, RalphAdmin): - readonly_fields = ['ldap_mapping', 'users_list'] + readonly_fields = ["ldap_mapping", "users_list"] fieldsets = ( - (None, {'fields': ['name', 'ldap_mapping', 'permissions']}), - ('Users', {'fields': ['users_list']}), + (None, {"fields": ["name", "ldap_mapping", "permissions"]}), + ("Users", {"fields": ["users_list"]}), ) @cached_property def _ldap_groups(self): - groups = {v: k for (k, v) in getattr( - settings, 'AUTH_LDAP_GROUP_MAPPING', {} - ).items()} - groups.update({v: k for (k, v) in getattr( - settings, 'AUTH_LDAP_NESTED_GROUPS', {} - ).items()}) + groups = { + v: k for (k, v) in getattr(settings, "AUTH_LDAP_GROUP_MAPPING", {}).items() + } + groups.update( + { + v: k + for (k, v) in getattr(settings, "AUTH_LDAP_NESTED_GROUPS", {}).items() + } + ) return groups def ldap_mapping(self, obj): - return self._ldap_groups.get(obj.name, '-') - ldap_mapping.short_description = _('LDAP mapping') + return self._ldap_groups.get(obj.name, "-") + + ldap_mapping.short_description = _("LDAP mapping") @mark_safe def users_list(self, obj): users = [] - for u in obj.user_set.order_by('username'): - users.append('{}'.format( - reverse("admin:accounts_ralphuser_change", args=(u.id,)), - str(u) - )) - return '
'.join(users) - users_list.short_description = _('Users list') + for u in obj.user_set.order_by("username"): + users.append( + '{}'.format( + reverse("admin:accounts_ralphuser_change", args=(u.id,)), str(u) + ) + ) + return "
".join(users) + + users_list.short_description = _("Users list") def formfield_for_manytomany(self, db_field, request=None, **kwargs): - if db_field.name == 'permissions': - qs = kwargs.get('queryset', db_field.remote_field.model.objects) + if db_field.name == "permissions": + qs = kwargs.get("queryset", db_field.remote_field.model.objects) if qs: qs = self._simplify_permissions(qs) - kwargs['queryset'] = qs - return super().formfield_for_manytomany( - db_field, request=request, **kwargs - ) + kwargs["queryset"] = qs + return super().formfield_for_manytomany(db_field, request=request, **kwargs) @register(Region) class RegionAdmin(RalphAdmin): - search_fields = ['name'] + search_fields = ["name"] @register(Team) class TeamAdmin(RalphAdmin): - search_fields = ['name'] + search_fields = ["name"] diff --git a/src/ralph/accounts/api.py b/src/ralph/accounts/api.py index 0ad2df80f1..57513f6572 100644 --- a/src/ralph/accounts/api.py +++ b/src/ralph/accounts/api.py @@ -8,7 +8,7 @@ from ralph.api.permissions import IsSuperuserOrReadonly from ralph.back_office.api import ( BackOfficeAssetSimpleSerializer, - BackOfficeAssetViewSet + BackOfficeAssetViewSet, ) from ralph.back_office.models import BackOfficeAsset from ralph.licences.api import LicenceUserViewSet @@ -19,7 +19,7 @@ class GroupSerializer(RalphAPISerializer): class Meta: model = Group - exclude = ('permissions',) + exclude = ("permissions",) class GroupViewSet(RalphAPIViewSet): @@ -31,8 +31,13 @@ class RalphUserSimpleSerializer(RalphAPISerializer): class Meta: model = get_user_model() fields = ( - 'id', 'url', 'username', 'first_name', 'last_name', 'email', - 'country', + "id", + "url", + "username", + "first_name", + "last_name", + "email", + "country", ) @@ -43,7 +48,7 @@ class RalphUserSerializer(RalphAPISerializer): class Meta: model = get_user_model() - exclude = ('user_permissions', 'password', 'groups') + exclude = ("user_permissions", "password", "groups") depth = 1 @@ -52,21 +57,21 @@ class RalphUserViewSet(RalphAPIViewSet): serializer_class = RalphUserSerializer _assets_queryset = BackOfficeAsset.objects.select_related( *BackOfficeAssetViewSet.select_related - ).prefetch_related('tags') + ).prefetch_related("tags") prefetch_related = [ - 'regions', 'user_permissions', - Prefetch('licences', queryset=LicenceUser.objects.select_related( - *LicenceUserViewSet.select_related - ).prefetch_related('licence__tags')), - Prefetch('assets_as_user', queryset=_assets_queryset), - Prefetch('assets_as_owner', queryset=_assets_queryset), - ] - permission_classes = RalphAPIViewSet.permission_classes + [ - IsSuperuserOrReadonly - ] - http_method_names = [ - m for m in RalphAPIViewSet.http_method_names if m != 'post' + "regions", + "user_permissions", + Prefetch( + "licences", + queryset=LicenceUser.objects.select_related( + *LicenceUserViewSet.select_related + ).prefetch_related("licence__tags"), + ), + Prefetch("assets_as_user", queryset=_assets_queryset), + Prefetch("assets_as_owner", queryset=_assets_queryset), ] + permission_classes = RalphAPIViewSet.permission_classes + [IsSuperuserOrReadonly] + http_method_names = [m for m in RalphAPIViewSet.http_method_names if m != "post"] class RegionSerializer(RalphAPISerializer): @@ -91,8 +96,8 @@ class TeamViewSet(RalphAPIViewSet): serializer_class = TeamSerializer -router.register(r'groups', GroupViewSet) -router.register(r'users', RalphUserViewSet) -router.register(r'regions', RegionViewSet) -router.register(r'teams', TeamViewSet) +router.register(r"groups", GroupViewSet) +router.register(r"users", RalphUserViewSet) +router.register(r"regions", RegionViewSet) +router.register(r"teams", TeamViewSet) urlpatterns = [] diff --git a/src/ralph/accounts/api_simple.py b/src/ralph/accounts/api_simple.py index 1eba6a18b5..984647dc0f 100644 --- a/src/ralph/accounts/api_simple.py +++ b/src/ralph/accounts/api_simple.py @@ -7,7 +7,7 @@ class SimpleRalphUserSerializer(RalphAPISerializer): class Meta: model = get_user_model() - fields = ('id', 'url', 'username', 'first_name', 'last_name') + fields = ("id", "url", "username", "first_name", "last_name") read_only_fields = fields depth = 1 @@ -15,16 +15,10 @@ class Meta: class ExtendedSimpleRalphUserSerializer(SimpleRalphUserSerializer): class Meta: model = get_user_model() - fields = SimpleRalphUserSerializer.Meta.fields + ( - 'department', - 'company' - ) + fields = SimpleRalphUserSerializer.Meta.fields + ("department", "company") class ExtendedRalphUserSerializer(ExtendedSimpleRalphUserSerializer): class Meta: model = get_user_model() - fields = ExtendedSimpleRalphUserSerializer.Meta.fields + ( - 'manager', - 'email' - ) + fields = ExtendedSimpleRalphUserSerializer.Meta.fields + ("manager", "email") diff --git a/src/ralph/accounts/apps.py b/src/ralph/accounts/apps.py index ec007caf4a..7c2e039150 100644 --- a/src/ralph/accounts/apps.py +++ b/src/ralph/accounts/apps.py @@ -5,12 +5,12 @@ class AccountsConfig(RalphAppConfig): - name = 'ralph.accounts' - verbose_name = _('Accounts') + name = "ralph.accounts" + verbose_name = _("Accounts") def ready(self): super().ready() try: - import ralph.accounts.ldap # noqa + import ralph.accounts.ldap # noqa except ImportError: pass diff --git a/src/ralph/accounts/helpers.py b/src/ralph/accounts/helpers.py index 7cbc9a9cb4..c85711635a 100644 --- a/src/ralph/accounts/helpers.py +++ b/src/ralph/accounts/helpers.py @@ -10,37 +10,59 @@ from ralph.lib.transitions.models import Transition from ralph.sim_cards.models import SIMCard -ACCEPTANCE_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_ID'] # noqa -ACCEPTANCE_SIM_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_SIM_ID'] # noqa -ACCEPTANCE_BACK_OFFICE_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_STATUS'] # noqa -ACCEPTANCE_SIMCARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['SIMCARD_ACCEPT_STATUS'] # noqa -ACCEPTANCE_LOAN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['LOAN_TRANSITION_ID'] # noqa -ACCEPTANCE_BACK_OFFICE_ACCEPT_LOAN_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_LOAN_STATUS'] # noqa -ACCEPTANCE_RETURN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['RETURN_TRANSITION_ID'] # noqa -ACCEPTANCE_BACK_OFFICE_RETURN_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_RETURN_STATUS'] # noqa -ACCEPTANCE_ACCESS_CARD_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_ACCESS_CARD_ID'] # noqa -ACCEPTANCE_ACCESS_CARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['ACCESS_CARD_ACCEPT_ACCEPT_STATUS'] # noqa -ACCEPTANCE_BACK_OFFICE_TEAM_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_TEAM_ACCEPT_STATUS'] # noqa -ACCEPTANCE_TEAM_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_TEAM_ACCEPT_ID'] # noqa -ACCEPTANCE_BACK_OFFICE_TEST_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_TEST_ACCEPT_STATUS'] # noqa -ACCEPTANCE_TEST_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_TEST_ACCEPT_ID'] # noqa +ACCEPTANCE_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "TRANSITION_ID" +] # noqa +ACCEPTANCE_SIM_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "TRANSITION_SIM_ID" +] # noqa +ACCEPTANCE_BACK_OFFICE_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "BACK_OFFICE_ACCEPT_STATUS" +] # noqa +ACCEPTANCE_SIMCARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "SIMCARD_ACCEPT_STATUS" +] # noqa +ACCEPTANCE_LOAN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "LOAN_TRANSITION_ID" +] # noqa +ACCEPTANCE_BACK_OFFICE_ACCEPT_LOAN_STATUS = ( + settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG["BACK_OFFICE_ACCEPT_LOAN_STATUS"] +) # noqa +ACCEPTANCE_RETURN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "RETURN_TRANSITION_ID" +] # noqa +ACCEPTANCE_BACK_OFFICE_RETURN_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "BACK_OFFICE_ACCEPT_RETURN_STATUS" +] # noqa +ACCEPTANCE_ACCESS_CARD_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "TRANSITION_ACCESS_CARD_ID" +] # noqa +ACCEPTANCE_ACCESS_CARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "ACCESS_CARD_ACCEPT_ACCEPT_STATUS" +] # noqa +ACCEPTANCE_BACK_OFFICE_TEAM_ACCEPT_STATUS = ( + settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG["BACK_OFFICE_TEAM_ACCEPT_STATUS"] +) # noqa +ACCEPTANCE_TEAM_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "TRANSITION_TEAM_ACCEPT_ID" +] # noqa +ACCEPTANCE_BACK_OFFICE_TEST_ACCEPT_STATUS = ( + settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG["BACK_OFFICE_TEST_ACCEPT_STATUS"] +) # noqa +ACCEPTANCE_TEST_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG[ + "TRANSITION_TEST_ACCEPT_ID" +] # noqa def transition_exists(transition_id): - return Transition.objects.filter( - id=transition_id - ).exists() + return Transition.objects.filter(id=transition_id).exists() -acceptance_transition_exists = partial( - transition_exists, ACCEPTANCE_TRANSITION_ID -) +acceptance_transition_exists = partial(transition_exists, ACCEPTANCE_TRANSITION_ID) acceptance_sim_transition_exists = partial( transition_exists, ACCEPTANCE_SIM_TRANSITION_ID ) -loan_transition_exists = partial( - transition_exists, ACCEPTANCE_LOAN_TRANSITION_ID -) +loan_transition_exists = partial(transition_exists, ACCEPTANCE_LOAN_TRANSITION_ID) acceptance_access_card_transition_exists = partial( transition_exists, ACCEPTANCE_ACCESS_CARD_TRANSITION_ID ) @@ -53,30 +75,19 @@ def transition_exists(transition_id): def get_assets(user, status): - return BackOfficeAsset.objects.filter( - status=status - ).filter(user=user) + return BackOfficeAsset.objects.filter(status=status).filter(user=user) def get_simcards(user, status): - return SIMCard.objects.filter( - status=status - ).filter(user=user) + return SIMCard.objects.filter(status=status).filter(user=user) def get_access_cards(user, status): - return AccessCard.objects.filter( - status=status, - user=user - ) + return AccessCard.objects.filter(status=status, user=user) -get_assets_to_accept = partial( - get_assets, status=ACCEPTANCE_BACK_OFFICE_ACCEPT_STATUS -) -get_simcards_to_accept = partial( - get_simcards, status=ACCEPTANCE_SIMCARD_ACCEPT_STATUS -) +get_assets_to_accept = partial(get_assets, status=ACCEPTANCE_BACK_OFFICE_ACCEPT_STATUS) +get_simcards_to_accept = partial(get_simcards, status=ACCEPTANCE_SIMCARD_ACCEPT_STATUS) get_assets_to_accept_loan = partial( get_assets, status=ACCEPTANCE_BACK_OFFICE_ACCEPT_LOAN_STATUS ) @@ -96,90 +107,76 @@ def get_access_cards(user, status): def get_acceptance_url(user): assets_to_accept = get_assets_to_accept(user) - admin_instance = ralph_site.get_admin_instance_for_model( - BackOfficeAsset - ) + admin_instance = ralph_site.get_admin_instance_for_model(BackOfficeAsset) url_name = admin_instance.get_transition_bulk_url_name() if assets_to_accept: url = reverse(url_name, args=(ACCEPTANCE_TRANSITION_ID,)) - query = urlencode([('select', a.id) for a in assets_to_accept]) - return '?'.join((url, query)) + query = urlencode([("select", a.id) for a in assets_to_accept]) + return "?".join((url, query)) return None def get_simcard_acceptance_url(user): assets_to_accept = get_simcards_to_accept(user) - admin_instance = ralph_site.get_admin_instance_for_model( - SIMCard - ) + admin_instance = ralph_site.get_admin_instance_for_model(SIMCard) url_name = admin_instance.get_transition_bulk_url_name() if assets_to_accept: url = reverse(url_name, args=(ACCEPTANCE_SIM_TRANSITION_ID,)) - query = urlencode([('select', a.id) for a in assets_to_accept]) - return '?'.join((url, query)) + query = urlencode([("select", a.id) for a in assets_to_accept]) + return "?".join((url, query)) return None def get_loan_acceptance_url(user): assets_to_accept = get_assets_to_accept_loan(user) - admin_instance = ralph_site.get_admin_instance_for_model( - BackOfficeAsset - ) + admin_instance = ralph_site.get_admin_instance_for_model(BackOfficeAsset) url_name = admin_instance.get_transition_bulk_url_name() if assets_to_accept: url = reverse(url_name, args=(ACCEPTANCE_LOAN_TRANSITION_ID,)) - query = urlencode([('select', a.id) for a in assets_to_accept]) - return '?'.join((url, query)) + query = urlencode([("select", a.id) for a in assets_to_accept]) + return "?".join((url, query)) return None def get_return_acceptance_url(user): assets_to_accept = get_assets_to_accept_return(user) - admin_instance = ralph_site.get_admin_instance_for_model( - BackOfficeAsset - ) + admin_instance = ralph_site.get_admin_instance_for_model(BackOfficeAsset) url_name = admin_instance.get_transition_bulk_url_name() if assets_to_accept: url = reverse(url_name, args=(ACCEPTANCE_RETURN_TRANSITION_ID,)) - query = urlencode([('select', a.id) for a in assets_to_accept]) - return '?'.join((url, query)) + query = urlencode([("select", a.id) for a in assets_to_accept]) + return "?".join((url, query)) return None def get_access_card_acceptance_url(user): assets_to_accept = get_access_cards_to_accept(user) - admin_instance = ralph_site.get_admin_instance_for_model( - AccessCard - ) + admin_instance = ralph_site.get_admin_instance_for_model(AccessCard) url_name = admin_instance.get_transition_bulk_url_name() if assets_to_accept: url = reverse(url_name, args=(ACCEPTANCE_ACCESS_CARD_TRANSITION_ID,)) - query = urlencode([('select', a.id) for a in assets_to_accept]) - return '?'.join((url, query)) + query = urlencode([("select", a.id) for a in assets_to_accept]) + return "?".join((url, query)) return None def get_team_asset_acceptance_url(user): assets_to_accept = get_team_assets_to_accept(user) - admin_instance = ralph_site.get_admin_instance_for_model( - BackOfficeAsset - ) + admin_instance = ralph_site.get_admin_instance_for_model(BackOfficeAsset) url_name = admin_instance.get_transition_bulk_url_name() if assets_to_accept: url = reverse(url_name, args=(ACCEPTANCE_TEAM_ACCEPT_TRANSITION_ID,)) - query = urlencode([('select', a.id) for a in assets_to_accept]) - return '?'.join((url, query)) + query = urlencode([("select", a.id) for a in assets_to_accept]) + return "?".join((url, query)) return None def get_test_asset_acceptance_url(user): assets_to_accept = get_test_assets_to_accept(user) - admin_instance = ralph_site.get_admin_instance_for_model( - BackOfficeAsset - ) + admin_instance = ralph_site.get_admin_instance_for_model(BackOfficeAsset) url_name = admin_instance.get_transition_bulk_url_name() if assets_to_accept: url = reverse(url_name, args=(ACCEPTANCE_TEST_ACCEPT_TRANSITION_ID,)) - query = urlencode([('select', a.id) for a in assets_to_accept]) - return '?'.join((url, query)) + query = urlencode([("select", a.id) for a in assets_to_accept]) + return "?".join((url, query)) return None diff --git a/src/ralph/accounts/ldap.py b/src/ralph/accounts/ldap.py index caf3380247..efa9b50f56 100644 --- a/src/ralph/accounts/ldap.py +++ b/src/ralph/accounts/ldap.py @@ -13,16 +13,16 @@ # Add default value to LDAPSetting dict. It will be replaced by # django_auth_ldap with value in settings.py and visible for each # ldap_user. -LDAPSettings.defaults['GROUP_MAPPING'] = {} +LDAPSettings.defaults["GROUP_MAPPING"] = {} @receiver(populate_user) def staff_superuser_populate(sender, user, ldap_user, **kwargs): - user.is_superuser = 'superuser' in ldap_user.group_names + user.is_superuser = "superuser" in ldap_user.group_names # only staff users will have access to ralph now, # because ralph using django admin panel - user.is_staff = 'active' in ldap_user.group_names - user.is_active = 'active' in ldap_user.group_names + user.is_staff = "active" in ldap_user.group_names + user.is_active = "active" in ldap_user.group_names def mirror_groups(self): @@ -32,39 +32,42 @@ def mirror_groups(self): """ target_group_names = frozenset(self._get_groups().get_group_names()) # the only difference comparing to original django_auth_ldap: - if getattr(settings, 'AUTH_LDAP_KEEP_NON_LDAP_GROUPS', False): + if getattr(settings, "AUTH_LDAP_KEEP_NON_LDAP_GROUPS", False): # list of groups names mapped from LDAP LDAP_GROUPS_NAMES = list( - getattr(settings, 'AUTH_LDAP_GROUP_MAPPING', {}).values() - ) + list( - getattr(settings, 'AUTH_LDAP_NESTED_GROUPS', {}).values() - ) + getattr(settings, "AUTH_LDAP_GROUP_MAPPING", {}).values() + ) + list(getattr(settings, "AUTH_LDAP_NESTED_GROUPS", {}).values()) # include groups not mapped from LDAP into target groups names non_ad_groups = list( self._user.groups.exclude(name__in=LDAP_GROUPS_NAMES).values_list( - 'name', flat=True + "name", flat=True ) ) target_group_names = frozenset(list(target_group_names) + non_ad_groups) - logger.info('Target groups for user {}: {}'.format( - self._user, ', '.join(target_group_names) - )) + logger.info( + "Target groups for user {}: {}".format( + self._user, ", ".join(target_group_names) + ) + ) current_group_names = frozenset( - self._user.groups.values_list('name', flat=True).iterator() + self._user.groups.values_list("name", flat=True).iterator() ) if target_group_names != current_group_names: - logger.info('Modifing user groups: current = {}, target = {}'.format( - ', '.join(current_group_names), ', '.join(target_group_names) - )) - existing_groups = list(Group.objects.filter( - name__in=target_group_names).iterator() + logger.info( + "Modifing user groups: current = {}, target = {}".format( + ", ".join(current_group_names), ", ".join(target_group_names) + ) ) - existing_group_names = frozenset( - group.name for group in existing_groups + existing_groups = list( + Group.objects.filter(name__in=target_group_names).iterator() ) + existing_group_names = frozenset(group.name for group in existing_groups) - new_groups = [Group.objects.get_or_create(name=name)[0] for name - in target_group_names if name not in existing_group_names] + new_groups = [ + Group.objects.get_or_create(name=name)[0] + for name in target_group_names + if name not in existing_group_names + ] self._user.groups.set(existing_groups + new_groups) @@ -74,27 +77,23 @@ def mirror_groups(self): @receiver(populate_user) -def manager_country_attribute_populate( - sender, user, ldap_user, **kwargs -): +def manager_country_attribute_populate(sender, user, ldap_user, **kwargs): try: profile_map = settings.AUTH_LDAP_USER_ATTR_MAP except AttributeError: profile_map = {} - if 'manager' in profile_map: - if profile_map['manager'] in ldap_user.attrs: - manager_ref = force_text( - ldap_user.attrs[profile_map['manager']][0] - ) + if "manager" in profile_map: + if profile_map["manager"] in ldap_user.attrs: + manager_ref = force_text(ldap_user.attrs[profile_map["manager"]][0]) # CN=John Smith,OU=TOR,OU=Corp-Users,DC=mydomain,DC=internal - cn = manager_ref.split(',')[0][3:] + cn = manager_ref.split(",")[0][3:] user.manager = cn # raw value from LDAP is in profile.country for this reason we assign # some correct value user.country = None - if 'country' in profile_map: - if profile_map['country'] in ldap_user.attrs: - country = force_text(ldap_user.attrs[profile_map['country']][0]) + if "country" in profile_map: + if profile_map["country"] in ldap_user.attrs: + country = force_text(ldap_user.attrs[profile_map["country"]][0]) # assign None if `country` doesn't exist in Country try: user.country = Country.id_from_name(country.lower()) diff --git a/src/ralph/accounts/ldap_helpers.py b/src/ralph/accounts/ldap_helpers.py index 2f7488ca9d..c5fa57a1a3 100644 --- a/src/ralph/accounts/ldap_helpers.py +++ b/src/ralph/accounts/ldap_helpers.py @@ -11,6 +11,7 @@ class MappedGroupOfNamesType(ActiveDirectoryGroupType): """Provide group mappings described in project settings.""" + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._ldap_groups = None @@ -24,13 +25,9 @@ def ldap_groups(self): Returns: dict with both flat and nested LDAP groups. """ if not self._ldap_groups: - logger.debug('Evaluating LDAP groupd from settings') - self._ldap_flat_groups = getattr( - settings, 'AUTH_LDAP_GROUP_MAPPING', {} - ) - self._ldap_nested_groups = getattr( - settings, 'AUTH_LDAP_NESTED_GROUPS', {} - ) + logger.debug("Evaluating LDAP groupd from settings") + self._ldap_flat_groups = getattr(settings, "AUTH_LDAP_GROUP_MAPPING", {}) + self._ldap_nested_groups = getattr(settings, "AUTH_LDAP_NESTED_GROUPS", {}) self._ldap_groups = self._ldap_flat_groups.copy() self._ldap_groups.update(self._ldap_nested_groups) return self._ldap_groups @@ -62,32 +59,26 @@ def handle_groups(groups_dns): # handle flat groups first (to which user belongs directly) try: - flat_groups_dns = set(map(force_text, ldap_user.attrs['memberOf'])) + flat_groups_dns = set(map(force_text, ldap_user.attrs["memberOf"])) except KeyError: flat_groups_dns = set() - logger.info('Flat groups DNs for {}: {}'.format( - username, flat_groups_dns - )) + logger.info("Flat groups DNs for {}: {}".format(username, flat_groups_dns)) handle_groups(flat_groups_dns) from ralph.accounts.management.commands.ldap_sync import get_nested_groups # noqa + # handle nested groups nested_groups_dns = get_nested_groups()[1].get(username, set()) - logger.info('Nested groups DNs for {}: {}'.format( - username, nested_groups_dns - )) + logger.info("Nested groups DNs for {}: {}".format(username, nested_groups_dns)) handle_groups(nested_groups_dns) return group_map def group_name_from_info(self, group_info): """Map ldap group names into ralph names if mapping defined.""" if self.ldap_groups: - for dn in group_info[1]['distinguishedname']: + for dn in group_info[1]["distinguishedname"]: mapped = self.ldap_groups.get(dn) if mapped: return mapped # return original name if mapping not defined else: - return super( - MappedGroupOfNamesType, - self - ).group_name_from_info(group_info) + return super(MappedGroupOfNamesType, self).group_name_from_info(group_info) diff --git a/src/ralph/accounts/management/commands/ldap_sync.py b/src/ralph/accounts/management/commands/ldap_sync.py index c592eeb207..541a3c7f00 100644 --- a/src/ralph/accounts/management/commands/ldap_sync.py +++ b/src/ralph/accounts/management/commands/ldap_sync.py @@ -19,6 +19,7 @@ try: import ldap from django_auth_ldap.backend import _LDAPUser + ldap_module_exists = True except ImportError: ldap_module_exists = False @@ -31,7 +32,7 @@ def decode_nested_dict(data): return [decode_nested_dict(element) for element in data] elif isinstance(data, bytes): try: - return data.decode('utf-8') + return data.decode("utf-8") except UnicodeDecodeError: return data else: @@ -78,51 +79,52 @@ def get_nested_groups(): group_users = {} # mapping from user (username) to set of groups DNs to which he belongs to users_groups = defaultdict(set) - nested_groups = getattr(settings, 'AUTH_LDAP_NESTED_GROUPS', None) + nested_groups = getattr(settings, "AUTH_LDAP_NESTED_GROUPS", None) if not nested_groups: return group_users, users_groups - nested_filter = getattr( - settings, 'AUTH_LDAP_NESTED_FILTER', '(memberOf:{})' - ) - logger.info('Fetching nested groups from LDAP') + nested_filter = getattr(settings, "AUTH_LDAP_NESTED_FILTER", "(memberOf:{})") + logger.info("Fetching nested groups from LDAP") with LDAPConnectionManager() as conn: for ldap_group_name, ralph_group_name in nested_groups.items(): ldap_filter = nested_filter.format(ldap_group_name) - logger.info('Fetching {}'.format(ralph_group_name)) + logger.info("Fetching {}".format(ralph_group_name)) users = _make_paged_query( - conn, settings.AUTH_LDAP_USER_SEARCH_BASE, ldap.SCOPE_SUBTREE, - '(&(objectClass={}){})'.format( + conn, + settings.AUTH_LDAP_USER_SEARCH_BASE, + ldap.SCOPE_SUBTREE, + "(&(objectClass={}){})".format( settings.LDAP_SERVER_OBJECT_USER_CLASS, ldap_filter ), [settings.AUTH_LDAP_USER_USERNAME_ATTR], - settings.AUTH_LDAP_QUERY_PAGE_SIZE + settings.AUTH_LDAP_QUERY_PAGE_SIZE, + ) + logger.info("{} fetched".format(ralph_group_name)) + group_users[ralph_group_name] = set( + [ + u[1][settings.AUTH_LDAP_USER_USERNAME_ATTR][0] + .decode("utf-8") + .lower() # noqa + for u in users + ] + ) + logger.info( + "Users in nested group {}: {}".format( + ralph_group_name, group_users[ralph_group_name] + ) ) - logger.info('{} fetched'.format(ralph_group_name)) - group_users[ralph_group_name] = set([ - u[1][settings.AUTH_LDAP_USER_USERNAME_ATTR][0].decode('utf-8').lower() # noqa - for u in users - ]) - logger.info('Users in nested group {}: {}'.format( - ralph_group_name, group_users[ralph_group_name] - )) for username in group_users[ralph_group_name]: # notice group DN here, not Django group name! users_groups[username].add(ldap_group_name) return group_users, users_groups -def _make_paged_query( - conn, search_base, search_scope, ad_query, attr_list, page_size -): +def _make_paged_query(conn, search_base, search_scope, ad_query, attr_list, page_size): """ Makes paged query to LDAP. Default max page size for LDAP is 1000. """ result = [] - page_result_control = SimplePagedResultsControl( - size=page_size, - cookie='' - ) + page_result_control = SimplePagedResultsControl(size=page_size, cookie="") msgid = conn.search_ext( search_base, @@ -160,6 +162,7 @@ class NestedGroups(object): group (get or create). django_auth_ldap and their class for nested group (NestedGroupOfNamesType) are inefficient. """ + def __init__(self): self.group_users, self.users_groups = get_nested_groups() @@ -179,12 +182,12 @@ def handle(self, user): if user.username in users: group = self.get_group_from_db(group_name) user.groups.add(group) - logger.info('Added {} to {}'.format(user.username, group_name)) + logger.info("Added {} to {}".format(user.username, group_name)) class Command(BaseCommand): - """Refresh info about users from ldap.""" + help = textwrap.dedent(__doc__).strip() def _create_or_update_user(self, user_dn, ldap_dict): @@ -199,10 +202,7 @@ def _disconnect(self): def _run_ldap_query(self, query): with LDAPConnectionManager() as conn: - lc = SimplePagedResultsControl( - size=LDAP_RESULTS_PAGE_SIZE, - cookie='' - ) + lc = SimplePagedResultsControl(size=LDAP_RESULTS_PAGE_SIZE, cookie="") msgid = conn.search_ext( settings.AUTH_LDAP_USER_SEARCH_BASE, ldap.SCOPE_SUBTREE, @@ -213,9 +213,12 @@ def _run_ldap_query(self, query): while True: page_num += 1 r_type, r_data, r_msgid, serverctrls = conn.result3(msgid) - logger.info('Pack of {} users loaded (page {})'.format( - LDAP_RESULTS_PAGE_SIZE, page_num, - )) + logger.info( + "Pack of {} users loaded (page {})".format( + LDAP_RESULTS_PAGE_SIZE, + page_num, + ) + ) for item in r_data: yield item if serverctrls: @@ -232,8 +235,8 @@ def _run_ldap_query(self, query): break else: logger.error( - 'LDAP::_run_ldap_query\tQuery: Server ignores RFC 2696 ' - 'control' + "LDAP::_run_ldap_query\tQuery: Server ignores RFC 2696 " + "control" ) sys.exit(1) @@ -242,47 +245,51 @@ def _get_users(self): try: user_filter = settings.AUTH_LDAP_USER_FILTER except AttributeError: - query = '(objectClass=%s)' % (objcls,) + query = "(objectClass=%s)" % (objcls,) else: - query = '(&(objectClass=%s)%s)' % (objcls, user_filter,) + query = "(&(objectClass=%s)%s)" % ( + objcls, + user_filter, + ) return self._run_ldap_query(query) def _load_backend(self): - path = settings.AUTHENTICATION_BACKENDS[0].split('.') + path = settings.AUTHENTICATION_BACKENDS[0].split(".") module_path = path[:-1] class_name = path[-1] - module = __import__('.'.join(module_path), globals(), locals(), - class_name) + module = __import__(".".join(module_path), globals(), locals(), class_name) self.backend = getattr(module, class_name)() def check_settings_existence(self): """Check if all needed settings are defined in settings.py""" options = [ - 'AUTH_LDAP_SERVER_URI', - 'AUTH_LDAP_USER_SEARCH_BASE', - 'AUTH_LDAP_USER_USERNAME_ATTR', - 'AUTH_LDAP_PROTOCOL_VERSION', - 'AUTH_LDAP_BIND_DN', - 'AUTH_LDAP_BIND_PASSWORD', + "AUTH_LDAP_SERVER_URI", + "AUTH_LDAP_USER_SEARCH_BASE", + "AUTH_LDAP_USER_USERNAME_ATTR", + "AUTH_LDAP_PROTOCOL_VERSION", + "AUTH_LDAP_BIND_DN", + "AUTH_LDAP_BIND_PASSWORD", ] for option in options: if not hasattr(settings, option): - logger.error('LDAP::check_settings_existence\tSetting %s is ' - 'not provided', option) + logger.error( + "LDAP::check_settings_existence\tSetting %s is " "not provided", + option, + ) sys.exit(1) def handle(self, *args, **kwargs): """Load users from ldap command.""" self.check_settings_existence() self._load_backend() - logger.info('Fetch nested groups...') + logger.info("Fetch nested groups...") self.nested_groups = NestedGroups() - logger.info('Syncing...') + logger.info("Syncing...") if not ldap_module_exists: - logger.error('ldap module not installed') - raise ImportError('No module named ldap') + logger.error("ldap module not installed") + raise ImportError("No module named ldap") synced = self.populate_users() - logger.info('LDAP users synced: %s', synced) + logger.info("LDAP users synced: %s", synced) def populate_users(self): """Load users from ldap and populate them. Returns number of users.""" @@ -290,7 +297,7 @@ def populate_users(self): for user_dn, ldap_dict in self._get_users(): # decode bytes to str ldap_dict = decode_nested_dict(ldap_dict) - _truncate('sn', 'last_name', ldap_dict) + _truncate("sn", "last_name", ldap_dict) user = self._create_or_update_user(user_dn, ldap_dict) self.nested_groups.handle(user) synced += 1 diff --git a/src/ralph/accounts/migrations/0001_initial.py b/src/ralph/accounts/migrations/0001_initial.py index 7e00344528..d53481599c 100644 --- a/src/ralph/accounts/migrations/0001_initial.py +++ b/src/ralph/accounts/migrations/0001_initial.py @@ -9,83 +9,491 @@ class Migration(migrations.Migration): - dependencies = [ - ('auth', '0006_require_contenttypes_0002'), + ("auth", "0006_require_contenttypes_0002"), ] operations = [ migrations.CreateModel( - name='RalphUser', + name="RalphUser", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('password', models.CharField(verbose_name='password', max_length=128)), - ('last_login', models.DateTimeField(verbose_name='last login', blank=True, null=True)), - ('is_superuser', models.BooleanField(verbose_name='superuser status', default=False, help_text='Designates that this user has all permissions without explicitly assigning them.')), - ('username', models.CharField(max_length=30, error_messages={'unique': 'A user with that username already exists.'}, verbose_name='username', help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], unique=True)), - ('first_name', models.CharField(verbose_name='first name', blank=True, max_length=30)), - ('last_name', models.CharField(verbose_name='last name', blank=True, max_length=30)), - ('email', models.EmailField(verbose_name='email address', blank=True, max_length=254)), - ('is_staff', models.BooleanField(verbose_name='staff status', default=False, help_text='Designates whether the user can log into this admin site.')), - ('is_active', models.BooleanField(verbose_name='active', default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.')), - ('date_joined', models.DateTimeField(verbose_name='date joined', default=django.utils.timezone.now)), - ('gender', models.PositiveIntegerField(verbose_name='gender', choices=[(1, 'female'), (2, 'male'), (3, 'unspecified')], default=2)), - ('country', models.PositiveIntegerField(verbose_name='country', choices=[(1, 'Afghanistan'), (2, 'Albania'), (3, 'Algeria'), (4, 'American Samoa'), (5, 'Andorra'), (6, 'Angola'), (7, 'Anguilla'), (8, 'Antarctica'), (9, 'Antigua and Barbuda'), (10, 'Argentina'), (11, 'Armenia'), (12, 'Aruba'), (13, 'Australia'), (14, 'Austria'), (15, 'Azerbaijan'), (16, 'Bahamas'), (17, 'Bahrain'), (18, 'Bangladesh'), (19, 'Barbados'), (20, 'Belarus'), (21, 'Belgium'), (22, 'Belize'), (23, 'Benin'), (24, 'Bermuda'), (25, 'Bhutan'), (26, 'Bolivia'), (27, 'Bosnia and Herzegovina'), (28, 'Botswana'), (29, 'Brazil'), (30, 'Brunei'), (31, 'Bulgaria'), (32, 'Burkina Faso'), (33, 'Burundi'), (34, 'Cambodia'), (35, 'Cameroon'), (36, 'Canada'), (37, 'Cape Verde'), (38, 'Cayman Islands'), (39, 'Central African Republic'), (40, 'Chad'), (41, 'Chile'), (42, 'China'), (43, 'Colombia'), (44, 'Comoros'), (45, 'Congo Brazzaville'), (46, 'Congo Kinshasa'), (47, 'Cook Islands'), (48, 'Costa Rica'), (49, 'Cote Divoire'), (50, 'Croatia'), (51, 'Cuba'), (52, 'Cyprus'), (53, 'Czech Republic'), (54, 'Denmark'), (55, 'Djibouti'), (56, 'Dominica'), (57, 'Dominican Republic'), (58, 'Ecuador'), (59, 'Egypt'), (60, 'El Salvador'), (61, 'Equatorial Guinea'), (62, 'Eritrea'), (63, 'Estonia'), (64, 'Ethiopia'), (65, 'Faroe Islands'), (66, 'Fiji'), (67, 'Finland'), (68, 'France'), (69, 'French Polynesia'), (70, 'Gabon'), (71, 'Gambia'), (72, 'Georgia'), (73, 'Germany'), (74, 'Ghana'), (75, 'Gibraltar'), (76, 'Greece'), (77, 'Grenada'), (78, 'Guam'), (79, 'Guatemala'), (80, 'Guinea Bissau'), (81, 'Guinea'), (82, 'Guyana'), (83, 'Haiti'), (84, 'Honduras'), (85, 'Hong Kong'), (86, 'Hungary'), (87, 'Iceland'), (88, 'India'), (89, 'Indonesia'), (90, 'Iran'), (91, 'Iraq'), (92, 'Ireland'), (93, 'Israel'), (94, 'Italy'), (95, 'Jamaica'), (96, 'Japan'), (97, 'Jersey'), (98, 'Jordan'), (99, 'Kazakhstan'), (100, 'Kenya'), (101, 'Kiribati'), (102, 'Kuwait'), (103, 'Kyrgyzstan'), (104, 'Laos'), (105, 'Latvia'), (106, 'Lebanon'), (107, 'Lesotho'), (108, 'Liberia'), (109, 'Libya'), (110, 'Liechtenstein'), (111, 'Lithuania'), (112, 'Luxembourg'), (113, 'Macau'), (114, 'Macedonia'), (115, 'Madagascar'), (116, 'Malawi'), (117, 'Malaysia'), (118, 'Maldives'), (119, 'Mali'), (120, 'Malta'), (121, 'Marshall Islands'), (122, 'Mauritania'), (123, 'Mauritius'), (124, 'Mexico'), (125, 'Micronesia'), (126, 'Moldova'), (127, 'Monaco'), (128, 'Mongolia'), (129, 'Montenegro'), (130, 'Montserrat'), (131, 'Morocco'), (132, 'Mozambique'), (133, 'Myanmar'), (134, 'Namibia'), (135, 'Nauru'), (136, 'Nepal'), (137, 'Netherlands Antilles'), (138, 'Netherlands'), (139, 'New Zealand'), (140, 'Nicaragua'), (141, 'Niger'), (142, 'Nigeria'), (143, 'North Korea'), (144, 'Norway'), (145, 'Oman'), (146, 'Pakistan'), (147, 'Palau'), (148, 'Panama'), (149, 'Papua New Guinea'), (150, 'Paraguay'), (151, 'Peru'), (152, 'Philippines'), (153, 'Poland'), (154, 'Portugal'), (155, 'Puerto Rico'), (156, 'Qatar'), (157, 'Romania'), (158, 'Russian Federation'), (159, 'Rwanda'), (160, 'Saint Lucia'), (161, 'Samoa'), (162, 'San Marino'), (163, 'Sao Tome and Principe'), (164, 'Saudi Arabia'), (165, 'Senegal'), (166, 'Serbia'), (167, 'Seychelles'), (168, 'Sierra Leone'), (169, 'Singapore'), (170, 'Slovakia'), (171, 'Slovenia'), (172, 'Solomon Islands'), (173, 'Somalia'), (174, 'South Africa'), (175, 'South Korea'), (176, 'Spain'), (177, 'Sri Lanka'), (178, 'St Kitts and Nevis'), (179, 'St Vincent and the Grenadines'), (180, 'Sudan'), (181, 'Suriname'), (182, 'Swaziland'), (183, 'Sweden'), (184, 'Switzerland'), (185, 'Syria'), (186, 'Tajikistan'), (187, 'Taiwan'), (188, 'Tanzania'), (189, 'Thailand'), (190, 'Timor Leste'), (191, 'Togo'), (192, 'Tonga'), (193, 'Trinidad and Tobago'), (194, 'Tunisia'), (195, 'Turkey'), (196, 'Turkmenistan'), (197, 'Turks and Caicos Islands'), (198, 'Tuvalu'), (199, 'Uganda'), (200, 'Ukraine'), (201, 'United Arab Emirates'), (202, 'United Kingdom'), (203, 'United States of America'), (204, 'Uruguay'), (205, 'Uzbekistan'), (206, 'Vanuatu'), (207, 'Vatican City'), (208, 'Venezuela'), (209, 'Viet Nam'), (210, 'Virgin Islands British'), (211, 'Virgin Islands US'), (212, 'Western Sahara'), (213, 'Yemen'), (214, 'Zambia'), (215, 'Zimbabwe'), (301, 'England'), (302, 'Northern Ireland'), (303, 'Wales'), (304, 'Scotland'), (601, 'Northern Cyprus'), (602, 'Palestine'), (603, 'Somaliland'), (901, 'African Union'), (902, 'Arab League'), (903, 'Association of Southeast Asian Nations'), (904, 'Caricom'), (905, 'Commonwealth of Independent States'), (906, 'Commonwealth of Nations'), (907, 'European Union'), (908, 'Islamic Conference'), (909, 'NATO'), (910, 'Olimpic Movement'), (911, 'OPEC'), (912, 'Red Cross'), (913, 'United Nations')], default=153)), - ('city', models.CharField(verbose_name='city', blank=True, max_length=30)), - ('company', models.CharField(verbose_name='company', blank=True, max_length=64)), - ('employee_id', models.CharField(verbose_name='employee id', blank=True, max_length=64)), - ('profit_center', models.CharField(verbose_name='profit center', blank=True, max_length=1024)), - ('cost_center', models.CharField(verbose_name='cost center', blank=True, max_length=1024)), - ('department', models.CharField(verbose_name='department', blank=True, max_length=64)), - ('manager', models.CharField(verbose_name='manager', blank=True, max_length=1024)), - ('location', models.CharField(verbose_name='location', blank=True, max_length=128)), - ('segment', models.CharField(verbose_name='segment', blank=True, max_length=256)), - ('groups', models.ManyToManyField(help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', verbose_name='groups', blank=True, to='auth.Group', related_query_name='user', related_name='user_set')), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("password", models.CharField(verbose_name="password", max_length=128)), + ( + "last_login", + models.DateTimeField( + verbose_name="last login", blank=True, null=True + ), + ), + ( + "is_superuser", + models.BooleanField( + verbose_name="superuser status", + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + ), + ), + ( + "username", + models.CharField( + max_length=30, + error_messages={ + "unique": "A user with that username already exists." + }, + verbose_name="username", + help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.", + validators=[ + django.core.validators.RegexValidator( + "^[\\w.@+-]+$", + "Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.", + "invalid", + ) + ], + unique=True, + ), + ), + ( + "first_name", + models.CharField( + verbose_name="first name", blank=True, max_length=30 + ), + ), + ( + "last_name", + models.CharField( + verbose_name="last name", blank=True, max_length=30 + ), + ), + ( + "email", + models.EmailField( + verbose_name="email address", blank=True, max_length=254 + ), + ), + ( + "is_staff", + models.BooleanField( + verbose_name="staff status", + default=False, + help_text="Designates whether the user can log into this admin site.", + ), + ), + ( + "is_active", + models.BooleanField( + verbose_name="active", + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + ), + ), + ( + "date_joined", + models.DateTimeField( + verbose_name="date joined", default=django.utils.timezone.now + ), + ), + ( + "gender", + models.PositiveIntegerField( + verbose_name="gender", + choices=[(1, "female"), (2, "male"), (3, "unspecified")], + default=2, + ), + ), + ( + "country", + models.PositiveIntegerField( + verbose_name="country", + choices=[ + (1, "Afghanistan"), + (2, "Albania"), + (3, "Algeria"), + (4, "American Samoa"), + (5, "Andorra"), + (6, "Angola"), + (7, "Anguilla"), + (8, "Antarctica"), + (9, "Antigua and Barbuda"), + (10, "Argentina"), + (11, "Armenia"), + (12, "Aruba"), + (13, "Australia"), + (14, "Austria"), + (15, "Azerbaijan"), + (16, "Bahamas"), + (17, "Bahrain"), + (18, "Bangladesh"), + (19, "Barbados"), + (20, "Belarus"), + (21, "Belgium"), + (22, "Belize"), + (23, "Benin"), + (24, "Bermuda"), + (25, "Bhutan"), + (26, "Bolivia"), + (27, "Bosnia and Herzegovina"), + (28, "Botswana"), + (29, "Brazil"), + (30, "Brunei"), + (31, "Bulgaria"), + (32, "Burkina Faso"), + (33, "Burundi"), + (34, "Cambodia"), + (35, "Cameroon"), + (36, "Canada"), + (37, "Cape Verde"), + (38, "Cayman Islands"), + (39, "Central African Republic"), + (40, "Chad"), + (41, "Chile"), + (42, "China"), + (43, "Colombia"), + (44, "Comoros"), + (45, "Congo Brazzaville"), + (46, "Congo Kinshasa"), + (47, "Cook Islands"), + (48, "Costa Rica"), + (49, "Cote Divoire"), + (50, "Croatia"), + (51, "Cuba"), + (52, "Cyprus"), + (53, "Czech Republic"), + (54, "Denmark"), + (55, "Djibouti"), + (56, "Dominica"), + (57, "Dominican Republic"), + (58, "Ecuador"), + (59, "Egypt"), + (60, "El Salvador"), + (61, "Equatorial Guinea"), + (62, "Eritrea"), + (63, "Estonia"), + (64, "Ethiopia"), + (65, "Faroe Islands"), + (66, "Fiji"), + (67, "Finland"), + (68, "France"), + (69, "French Polynesia"), + (70, "Gabon"), + (71, "Gambia"), + (72, "Georgia"), + (73, "Germany"), + (74, "Ghana"), + (75, "Gibraltar"), + (76, "Greece"), + (77, "Grenada"), + (78, "Guam"), + (79, "Guatemala"), + (80, "Guinea Bissau"), + (81, "Guinea"), + (82, "Guyana"), + (83, "Haiti"), + (84, "Honduras"), + (85, "Hong Kong"), + (86, "Hungary"), + (87, "Iceland"), + (88, "India"), + (89, "Indonesia"), + (90, "Iran"), + (91, "Iraq"), + (92, "Ireland"), + (93, "Israel"), + (94, "Italy"), + (95, "Jamaica"), + (96, "Japan"), + (97, "Jersey"), + (98, "Jordan"), + (99, "Kazakhstan"), + (100, "Kenya"), + (101, "Kiribati"), + (102, "Kuwait"), + (103, "Kyrgyzstan"), + (104, "Laos"), + (105, "Latvia"), + (106, "Lebanon"), + (107, "Lesotho"), + (108, "Liberia"), + (109, "Libya"), + (110, "Liechtenstein"), + (111, "Lithuania"), + (112, "Luxembourg"), + (113, "Macau"), + (114, "Macedonia"), + (115, "Madagascar"), + (116, "Malawi"), + (117, "Malaysia"), + (118, "Maldives"), + (119, "Mali"), + (120, "Malta"), + (121, "Marshall Islands"), + (122, "Mauritania"), + (123, "Mauritius"), + (124, "Mexico"), + (125, "Micronesia"), + (126, "Moldova"), + (127, "Monaco"), + (128, "Mongolia"), + (129, "Montenegro"), + (130, "Montserrat"), + (131, "Morocco"), + (132, "Mozambique"), + (133, "Myanmar"), + (134, "Namibia"), + (135, "Nauru"), + (136, "Nepal"), + (137, "Netherlands Antilles"), + (138, "Netherlands"), + (139, "New Zealand"), + (140, "Nicaragua"), + (141, "Niger"), + (142, "Nigeria"), + (143, "North Korea"), + (144, "Norway"), + (145, "Oman"), + (146, "Pakistan"), + (147, "Palau"), + (148, "Panama"), + (149, "Papua New Guinea"), + (150, "Paraguay"), + (151, "Peru"), + (152, "Philippines"), + (153, "Poland"), + (154, "Portugal"), + (155, "Puerto Rico"), + (156, "Qatar"), + (157, "Romania"), + (158, "Russian Federation"), + (159, "Rwanda"), + (160, "Saint Lucia"), + (161, "Samoa"), + (162, "San Marino"), + (163, "Sao Tome and Principe"), + (164, "Saudi Arabia"), + (165, "Senegal"), + (166, "Serbia"), + (167, "Seychelles"), + (168, "Sierra Leone"), + (169, "Singapore"), + (170, "Slovakia"), + (171, "Slovenia"), + (172, "Solomon Islands"), + (173, "Somalia"), + (174, "South Africa"), + (175, "South Korea"), + (176, "Spain"), + (177, "Sri Lanka"), + (178, "St Kitts and Nevis"), + (179, "St Vincent and the Grenadines"), + (180, "Sudan"), + (181, "Suriname"), + (182, "Swaziland"), + (183, "Sweden"), + (184, "Switzerland"), + (185, "Syria"), + (186, "Tajikistan"), + (187, "Taiwan"), + (188, "Tanzania"), + (189, "Thailand"), + (190, "Timor Leste"), + (191, "Togo"), + (192, "Tonga"), + (193, "Trinidad and Tobago"), + (194, "Tunisia"), + (195, "Turkey"), + (196, "Turkmenistan"), + (197, "Turks and Caicos Islands"), + (198, "Tuvalu"), + (199, "Uganda"), + (200, "Ukraine"), + (201, "United Arab Emirates"), + (202, "United Kingdom"), + (203, "United States of America"), + (204, "Uruguay"), + (205, "Uzbekistan"), + (206, "Vanuatu"), + (207, "Vatican City"), + (208, "Venezuela"), + (209, "Viet Nam"), + (210, "Virgin Islands British"), + (211, "Virgin Islands US"), + (212, "Western Sahara"), + (213, "Yemen"), + (214, "Zambia"), + (215, "Zimbabwe"), + (301, "England"), + (302, "Northern Ireland"), + (303, "Wales"), + (304, "Scotland"), + (601, "Northern Cyprus"), + (602, "Palestine"), + (603, "Somaliland"), + (901, "African Union"), + (902, "Arab League"), + (903, "Association of Southeast Asian Nations"), + (904, "Caricom"), + (905, "Commonwealth of Independent States"), + (906, "Commonwealth of Nations"), + (907, "European Union"), + (908, "Islamic Conference"), + (909, "NATO"), + (910, "Olimpic Movement"), + (911, "OPEC"), + (912, "Red Cross"), + (913, "United Nations"), + ], + default=153, + ), + ), + ( + "city", + models.CharField(verbose_name="city", blank=True, max_length=30), + ), + ( + "company", + models.CharField(verbose_name="company", blank=True, max_length=64), + ), + ( + "employee_id", + models.CharField( + verbose_name="employee id", blank=True, max_length=64 + ), + ), + ( + "profit_center", + models.CharField( + verbose_name="profit center", blank=True, max_length=1024 + ), + ), + ( + "cost_center", + models.CharField( + verbose_name="cost center", blank=True, max_length=1024 + ), + ), + ( + "department", + models.CharField( + verbose_name="department", blank=True, max_length=64 + ), + ), + ( + "manager", + models.CharField( + verbose_name="manager", blank=True, max_length=1024 + ), + ), + ( + "location", + models.CharField( + verbose_name="location", blank=True, max_length=128 + ), + ), + ( + "segment", + models.CharField( + verbose_name="segment", blank=True, max_length=256 + ), + ), + ( + "groups", + models.ManyToManyField( + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + verbose_name="groups", + blank=True, + to="auth.Group", + related_query_name="user", + related_name="user_set", + ), + ), ], options={ - 'verbose_name': 'user', - 'abstract': False, - 'verbose_name_plural': 'users', - 'swappable': 'AUTH_USER_MODEL', + "verbose_name": "user", + "abstract": False, + "verbose_name_plural": "users", + "swappable": "AUTH_USER_MODEL", }, bases=(models.Model, ralph.lib.mixins.models.AdminAbsoluteUrlMixin), managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ("objects", django.contrib.auth.models.UserManager()), ], ), migrations.CreateModel( - name='Region', + name="Region", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='Team', + name="Team", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.AddField( - model_name='ralphuser', - name='regions', - field=models.ManyToManyField(blank=True, to='accounts.Region', related_name='users'), + model_name="ralphuser", + name="regions", + field=models.ManyToManyField( + blank=True, to="accounts.Region", related_name="users" + ), ), migrations.AddField( - model_name='ralphuser', - name='team', - field=models.ForeignKey(to='accounts.Team', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="ralphuser", + name="team", + field=models.ForeignKey( + to="accounts.Team", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='ralphuser', - name='user_permissions', - field=models.ManyToManyField(help_text='Specific permissions for this user.', verbose_name='user permissions', blank=True, to='auth.Permission', related_query_name='user', related_name='user_set'), + model_name="ralphuser", + name="user_permissions", + field=models.ManyToManyField( + help_text="Specific permissions for this user.", + verbose_name="user permissions", + blank=True, + to="auth.Permission", + related_query_name="user", + related_name="user_set", + ), ), ] diff --git a/src/ralph/accounts/migrations/0002_auto_20151204_0758.py b/src/ralph/accounts/migrations/0002_auto_20151204_0758.py index 7acdeae7b8..2b10cc20b1 100644 --- a/src/ralph/accounts/migrations/0002_auto_20151204_0758.py +++ b/src/ralph/accounts/migrations/0002_auto_20151204_0758.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0001_initial'), + ("accounts", "0001_initial"), ] operations = [ migrations.AlterModelOptions( - name='team', - options={'ordering': ['name']}, + name="team", + options={"ordering": ["name"]}, ), ] diff --git a/src/ralph/accounts/migrations/0003_region_country.py b/src/ralph/accounts/migrations/0003_region_country.py index f6e49823fc..0f88176210 100644 --- a/src/ralph/accounts/migrations/0003_region_country.py +++ b/src/ralph/accounts/migrations/0003_region_country.py @@ -5,15 +5,254 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0002_auto_20151204_0758'), + ("accounts", "0002_auto_20151204_0758"), ] operations = [ migrations.AddField( - model_name='region', - name='country', - field=models.PositiveIntegerField(default=153, verbose_name='country', choices=[(1, 'Afghanistan'), (2, 'Albania'), (3, 'Algeria'), (4, 'American Samoa'), (5, 'Andorra'), (6, 'Angola'), (7, 'Anguilla'), (8, 'Antarctica'), (9, 'Antigua and Barbuda'), (10, 'Argentina'), (11, 'Armenia'), (12, 'Aruba'), (13, 'Australia'), (14, 'Austria'), (15, 'Azerbaijan'), (16, 'Bahamas'), (17, 'Bahrain'), (18, 'Bangladesh'), (19, 'Barbados'), (20, 'Belarus'), (21, 'Belgium'), (22, 'Belize'), (23, 'Benin'), (24, 'Bermuda'), (25, 'Bhutan'), (26, 'Bolivia'), (27, 'Bosnia and Herzegovina'), (28, 'Botswana'), (29, 'Brazil'), (30, 'Brunei'), (31, 'Bulgaria'), (32, 'Burkina Faso'), (33, 'Burundi'), (34, 'Cambodia'), (35, 'Cameroon'), (36, 'Canada'), (37, 'Cape Verde'), (38, 'Cayman Islands'), (39, 'Central African Republic'), (40, 'Chad'), (41, 'Chile'), (42, 'China'), (43, 'Colombia'), (44, 'Comoros'), (45, 'Congo Brazzaville'), (46, 'Congo Kinshasa'), (47, 'Cook Islands'), (48, 'Costa Rica'), (49, 'Cote Divoire'), (50, 'Croatia'), (51, 'Cuba'), (52, 'Cyprus'), (53, 'Czech Republic'), (54, 'Denmark'), (55, 'Djibouti'), (56, 'Dominica'), (57, 'Dominican Republic'), (58, 'Ecuador'), (59, 'Egypt'), (60, 'El Salvador'), (61, 'Equatorial Guinea'), (62, 'Eritrea'), (63, 'Estonia'), (64, 'Ethiopia'), (65, 'Faroe Islands'), (66, 'Fiji'), (67, 'Finland'), (68, 'France'), (69, 'French Polynesia'), (70, 'Gabon'), (71, 'Gambia'), (72, 'Georgia'), (73, 'Germany'), (74, 'Ghana'), (75, 'Gibraltar'), (76, 'Greece'), (77, 'Grenada'), (78, 'Guam'), (79, 'Guatemala'), (80, 'Guinea Bissau'), (81, 'Guinea'), (82, 'Guyana'), (83, 'Haiti'), (84, 'Honduras'), (85, 'Hong Kong'), (86, 'Hungary'), (87, 'Iceland'), (88, 'India'), (89, 'Indonesia'), (90, 'Iran'), (91, 'Iraq'), (92, 'Ireland'), (93, 'Israel'), (94, 'Italy'), (95, 'Jamaica'), (96, 'Japan'), (97, 'Jersey'), (98, 'Jordan'), (99, 'Kazakhstan'), (100, 'Kenya'), (101, 'Kiribati'), (102, 'Kuwait'), (103, 'Kyrgyzstan'), (104, 'Laos'), (105, 'Latvia'), (106, 'Lebanon'), (107, 'Lesotho'), (108, 'Liberia'), (109, 'Libya'), (110, 'Liechtenstein'), (111, 'Lithuania'), (112, 'Luxembourg'), (113, 'Macau'), (114, 'Macedonia'), (115, 'Madagascar'), (116, 'Malawi'), (117, 'Malaysia'), (118, 'Maldives'), (119, 'Mali'), (120, 'Malta'), (121, 'Marshall Islands'), (122, 'Mauritania'), (123, 'Mauritius'), (124, 'Mexico'), (125, 'Micronesia'), (126, 'Moldova'), (127, 'Monaco'), (128, 'Mongolia'), (129, 'Montenegro'), (130, 'Montserrat'), (131, 'Morocco'), (132, 'Mozambique'), (133, 'Myanmar'), (134, 'Namibia'), (135, 'Nauru'), (136, 'Nepal'), (137, 'Netherlands Antilles'), (138, 'Netherlands'), (139, 'New Zealand'), (140, 'Nicaragua'), (141, 'Niger'), (142, 'Nigeria'), (143, 'North Korea'), (144, 'Norway'), (145, 'Oman'), (146, 'Pakistan'), (147, 'Palau'), (148, 'Panama'), (149, 'Papua New Guinea'), (150, 'Paraguay'), (151, 'Peru'), (152, 'Philippines'), (153, 'Poland'), (154, 'Portugal'), (155, 'Puerto Rico'), (156, 'Qatar'), (157, 'Romania'), (158, 'Russian Federation'), (159, 'Rwanda'), (160, 'Saint Lucia'), (161, 'Samoa'), (162, 'San Marino'), (163, 'Sao Tome and Principe'), (164, 'Saudi Arabia'), (165, 'Senegal'), (166, 'Serbia'), (167, 'Seychelles'), (168, 'Sierra Leone'), (169, 'Singapore'), (170, 'Slovakia'), (171, 'Slovenia'), (172, 'Solomon Islands'), (173, 'Somalia'), (174, 'South Africa'), (175, 'South Korea'), (176, 'Spain'), (177, 'Sri Lanka'), (178, 'St Kitts and Nevis'), (179, 'St Vincent and the Grenadines'), (180, 'Sudan'), (181, 'Suriname'), (182, 'Swaziland'), (183, 'Sweden'), (184, 'Switzerland'), (185, 'Syria'), (186, 'Tajikistan'), (187, 'Taiwan'), (188, 'Tanzania'), (189, 'Thailand'), (190, 'Timor Leste'), (191, 'Togo'), (192, 'Tonga'), (193, 'Trinidad and Tobago'), (194, 'Tunisia'), (195, 'Turkey'), (196, 'Turkmenistan'), (197, 'Turks and Caicos Islands'), (198, 'Tuvalu'), (199, 'Uganda'), (200, 'Ukraine'), (201, 'United Arab Emirates'), (202, 'United Kingdom'), (203, 'United States of America'), (204, 'Uruguay'), (205, 'Uzbekistan'), (206, 'Vanuatu'), (207, 'Vatican City'), (208, 'Venezuela'), (209, 'Viet Nam'), (210, 'Virgin Islands British'), (211, 'Virgin Islands US'), (212, 'Western Sahara'), (213, 'Yemen'), (214, 'Zambia'), (215, 'Zimbabwe'), (301, 'England'), (302, 'Northern Ireland'), (303, 'Wales'), (304, 'Scotland'), (601, 'Northern Cyprus'), (602, 'Palestine'), (603, 'Somaliland'), (901, 'African Union'), (902, 'Arab League'), (903, 'Association of Southeast Asian Nations'), (904, 'Caricom'), (905, 'Commonwealth of Independent States'), (906, 'Commonwealth of Nations'), (907, 'European Union'), (908, 'Islamic Conference'), (909, 'NATO'), (910, 'Olimpic Movement'), (911, 'OPEC'), (912, 'Red Cross'), (913, 'United Nations')]), + model_name="region", + name="country", + field=models.PositiveIntegerField( + default=153, + verbose_name="country", + choices=[ + (1, "Afghanistan"), + (2, "Albania"), + (3, "Algeria"), + (4, "American Samoa"), + (5, "Andorra"), + (6, "Angola"), + (7, "Anguilla"), + (8, "Antarctica"), + (9, "Antigua and Barbuda"), + (10, "Argentina"), + (11, "Armenia"), + (12, "Aruba"), + (13, "Australia"), + (14, "Austria"), + (15, "Azerbaijan"), + (16, "Bahamas"), + (17, "Bahrain"), + (18, "Bangladesh"), + (19, "Barbados"), + (20, "Belarus"), + (21, "Belgium"), + (22, "Belize"), + (23, "Benin"), + (24, "Bermuda"), + (25, "Bhutan"), + (26, "Bolivia"), + (27, "Bosnia and Herzegovina"), + (28, "Botswana"), + (29, "Brazil"), + (30, "Brunei"), + (31, "Bulgaria"), + (32, "Burkina Faso"), + (33, "Burundi"), + (34, "Cambodia"), + (35, "Cameroon"), + (36, "Canada"), + (37, "Cape Verde"), + (38, "Cayman Islands"), + (39, "Central African Republic"), + (40, "Chad"), + (41, "Chile"), + (42, "China"), + (43, "Colombia"), + (44, "Comoros"), + (45, "Congo Brazzaville"), + (46, "Congo Kinshasa"), + (47, "Cook Islands"), + (48, "Costa Rica"), + (49, "Cote Divoire"), + (50, "Croatia"), + (51, "Cuba"), + (52, "Cyprus"), + (53, "Czech Republic"), + (54, "Denmark"), + (55, "Djibouti"), + (56, "Dominica"), + (57, "Dominican Republic"), + (58, "Ecuador"), + (59, "Egypt"), + (60, "El Salvador"), + (61, "Equatorial Guinea"), + (62, "Eritrea"), + (63, "Estonia"), + (64, "Ethiopia"), + (65, "Faroe Islands"), + (66, "Fiji"), + (67, "Finland"), + (68, "France"), + (69, "French Polynesia"), + (70, "Gabon"), + (71, "Gambia"), + (72, "Georgia"), + (73, "Germany"), + (74, "Ghana"), + (75, "Gibraltar"), + (76, "Greece"), + (77, "Grenada"), + (78, "Guam"), + (79, "Guatemala"), + (80, "Guinea Bissau"), + (81, "Guinea"), + (82, "Guyana"), + (83, "Haiti"), + (84, "Honduras"), + (85, "Hong Kong"), + (86, "Hungary"), + (87, "Iceland"), + (88, "India"), + (89, "Indonesia"), + (90, "Iran"), + (91, "Iraq"), + (92, "Ireland"), + (93, "Israel"), + (94, "Italy"), + (95, "Jamaica"), + (96, "Japan"), + (97, "Jersey"), + (98, "Jordan"), + (99, "Kazakhstan"), + (100, "Kenya"), + (101, "Kiribati"), + (102, "Kuwait"), + (103, "Kyrgyzstan"), + (104, "Laos"), + (105, "Latvia"), + (106, "Lebanon"), + (107, "Lesotho"), + (108, "Liberia"), + (109, "Libya"), + (110, "Liechtenstein"), + (111, "Lithuania"), + (112, "Luxembourg"), + (113, "Macau"), + (114, "Macedonia"), + (115, "Madagascar"), + (116, "Malawi"), + (117, "Malaysia"), + (118, "Maldives"), + (119, "Mali"), + (120, "Malta"), + (121, "Marshall Islands"), + (122, "Mauritania"), + (123, "Mauritius"), + (124, "Mexico"), + (125, "Micronesia"), + (126, "Moldova"), + (127, "Monaco"), + (128, "Mongolia"), + (129, "Montenegro"), + (130, "Montserrat"), + (131, "Morocco"), + (132, "Mozambique"), + (133, "Myanmar"), + (134, "Namibia"), + (135, "Nauru"), + (136, "Nepal"), + (137, "Netherlands Antilles"), + (138, "Netherlands"), + (139, "New Zealand"), + (140, "Nicaragua"), + (141, "Niger"), + (142, "Nigeria"), + (143, "North Korea"), + (144, "Norway"), + (145, "Oman"), + (146, "Pakistan"), + (147, "Palau"), + (148, "Panama"), + (149, "Papua New Guinea"), + (150, "Paraguay"), + (151, "Peru"), + (152, "Philippines"), + (153, "Poland"), + (154, "Portugal"), + (155, "Puerto Rico"), + (156, "Qatar"), + (157, "Romania"), + (158, "Russian Federation"), + (159, "Rwanda"), + (160, "Saint Lucia"), + (161, "Samoa"), + (162, "San Marino"), + (163, "Sao Tome and Principe"), + (164, "Saudi Arabia"), + (165, "Senegal"), + (166, "Serbia"), + (167, "Seychelles"), + (168, "Sierra Leone"), + (169, "Singapore"), + (170, "Slovakia"), + (171, "Slovenia"), + (172, "Solomon Islands"), + (173, "Somalia"), + (174, "South Africa"), + (175, "South Korea"), + (176, "Spain"), + (177, "Sri Lanka"), + (178, "St Kitts and Nevis"), + (179, "St Vincent and the Grenadines"), + (180, "Sudan"), + (181, "Suriname"), + (182, "Swaziland"), + (183, "Sweden"), + (184, "Switzerland"), + (185, "Syria"), + (186, "Tajikistan"), + (187, "Taiwan"), + (188, "Tanzania"), + (189, "Thailand"), + (190, "Timor Leste"), + (191, "Togo"), + (192, "Tonga"), + (193, "Trinidad and Tobago"), + (194, "Tunisia"), + (195, "Turkey"), + (196, "Turkmenistan"), + (197, "Turks and Caicos Islands"), + (198, "Tuvalu"), + (199, "Uganda"), + (200, "Ukraine"), + (201, "United Arab Emirates"), + (202, "United Kingdom"), + (203, "United States of America"), + (204, "Uruguay"), + (205, "Uzbekistan"), + (206, "Vanuatu"), + (207, "Vatican City"), + (208, "Venezuela"), + (209, "Viet Nam"), + (210, "Virgin Islands British"), + (211, "Virgin Islands US"), + (212, "Western Sahara"), + (213, "Yemen"), + (214, "Zambia"), + (215, "Zimbabwe"), + (301, "England"), + (302, "Northern Ireland"), + (303, "Wales"), + (304, "Scotland"), + (601, "Northern Cyprus"), + (602, "Palestine"), + (603, "Somaliland"), + (901, "African Union"), + (902, "Arab League"), + (903, "Association of Southeast Asian Nations"), + (904, "Caricom"), + (905, "Commonwealth of Independent States"), + (906, "Commonwealth of Nations"), + (907, "European Union"), + (908, "Islamic Conference"), + (909, "NATO"), + (910, "Olimpic Movement"), + (911, "OPEC"), + (912, "Red Cross"), + (913, "United Nations"), + ], + ), ), ] diff --git a/src/ralph/accounts/migrations/0004_region_stocktaking_enabled.py b/src/ralph/accounts/migrations/0004_region_stocktaking_enabled.py index 3081ec4e43..3495127f23 100644 --- a/src/ralph/accounts/migrations/0004_region_stocktaking_enabled.py +++ b/src/ralph/accounts/migrations/0004_region_stocktaking_enabled.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0003_region_country'), + ("accounts", "0003_region_country"), ] operations = [ migrations.AddField( - model_name='region', - name='stocktaking_enabled', + model_name="region", + name="stocktaking_enabled", field=models.BooleanField(default=False), ), ] diff --git a/src/ralph/accounts/migrations/0005_auto_20170814_1636.py b/src/ralph/accounts/migrations/0005_auto_20170814_1636.py index 0a2ea75719..6ba1ab4318 100644 --- a/src/ralph/accounts/migrations/0005_auto_20170814_1636.py +++ b/src/ralph/accounts/migrations/0005_auto_20170814_1636.py @@ -5,15 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0004_region_stocktaking_enabled'), + ("accounts", "0004_region_stocktaking_enabled"), ] operations = [ migrations.AlterField( - model_name='ralphuser', - name='gender', - field=models.PositiveIntegerField(choices=[(1, 'female'), (2, 'male'), (3, 'unspecified')], verbose_name='gender', default=3), + model_name="ralphuser", + name="gender", + field=models.PositiveIntegerField( + choices=[(1, "female"), (2, "male"), (3, "unspecified")], + verbose_name="gender", + default=3, + ), ), ] diff --git a/src/ralph/accounts/migrations/0006_remove_ralphuser_gender.py b/src/ralph/accounts/migrations/0006_remove_ralphuser_gender.py index ff0aeb1f62..736bdb8bae 100644 --- a/src/ralph/accounts/migrations/0006_remove_ralphuser_gender.py +++ b/src/ralph/accounts/migrations/0006_remove_ralphuser_gender.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0005_auto_20170814_1636'), + ("accounts", "0005_auto_20170814_1636"), ] operations = [ migrations.RemoveField( - model_name='ralphuser', - name='gender', + model_name="ralphuser", + name="gender", ), ] diff --git a/src/ralph/accounts/migrations/0007_auto_20240506_1128.py b/src/ralph/accounts/migrations/0007_auto_20240506_1128.py index 80aef8bd63..386ec44669 100644 --- a/src/ralph/accounts/migrations/0007_auto_20240506_1128.py +++ b/src/ralph/accounts/migrations/0007_auto_20240506_1128.py @@ -7,15 +7,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0006_remove_ralphuser_gender'), + ("accounts", "0006_remove_ralphuser_gender"), ] operations = [ migrations.AlterField( - model_name='ralphuser', - name='username', - field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')], verbose_name='username'), + model_name="ralphuser", + name="username", + field=models.CharField( + error_messages={"unique": "A user with that username already exists."}, + help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=30, + unique=True, + validators=[ + django.core.validators.RegexValidator( + "^[\\w.@+-]+$", + "Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.", + ) + ], + verbose_name="username", + ), ), ] diff --git a/src/ralph/accounts/migrations/0008_auto_20240507_1422.py b/src/ralph/accounts/migrations/0008_auto_20240507_1422.py index 634fb4f39b..f0fbff37a5 100644 --- a/src/ralph/accounts/migrations/0008_auto_20240507_1422.py +++ b/src/ralph/accounts/migrations/0008_auto_20240507_1422.py @@ -7,15 +7,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0007_auto_20240506_1128'), + ("accounts", "0007_auto_20240506_1128"), ] operations = [ migrations.AlterField( - model_name='ralphuser', - name='username', - field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username'), + model_name="ralphuser", + name="username", + field=models.CharField( + error_messages={"unique": "A user with that username already exists."}, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], + verbose_name="username", + ), ), ] diff --git a/src/ralph/accounts/migrations/0009_auto_20240621_1217.py b/src/ralph/accounts/migrations/0009_auto_20240621_1217.py index 7083d8826f..7c911d3135 100644 --- a/src/ralph/accounts/migrations/0009_auto_20240621_1217.py +++ b/src/ralph/accounts/migrations/0009_auto_20240621_1217.py @@ -4,15 +4,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0008_auto_20240507_1422'), + ("accounts", "0008_auto_20240507_1422"), ] operations = [ migrations.AlterField( - model_name='ralphuser', - name='last_name', - field=models.CharField(blank=True, max_length=150, verbose_name='last name'), + model_name="ralphuser", + name="last_name", + field=models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), ), ] diff --git a/src/ralph/accounts/migrations/0010_auto_20241030_1235.py b/src/ralph/accounts/migrations/0010_auto_20241030_1235.py index 41c9d3b7ca..e9650420c4 100644 --- a/src/ralph/accounts/migrations/0010_auto_20241030_1235.py +++ b/src/ralph/accounts/migrations/0010_auto_20241030_1235.py @@ -4,15 +4,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0009_auto_20240621_1217'), + ("accounts", "0009_auto_20240621_1217"), ] operations = [ migrations.AlterField( - model_name='ralphuser', - name='department', - field=models.CharField(blank=True, max_length=128, verbose_name='department'), + model_name="ralphuser", + name="department", + field=models.CharField( + blank=True, max_length=128, verbose_name="department" + ), ), ] diff --git a/src/ralph/accounts/models.py b/src/ralph/accounts/models.py index bff526468b..1e2e262ce8 100644 --- a/src/ralph/accounts/models.py +++ b/src/ralph/accounts/models.py @@ -16,7 +16,7 @@ from ralph.lib.permissions.models import ( PermByFieldMixin, PermissionsForObjectMixin, - user_permission + user_permission, ) @@ -30,13 +30,14 @@ def has_region(user): class Region(AdminAbsoluteUrlMixin, PermissionsForObjectMixin, NamedMixin): country = models.PositiveIntegerField( - verbose_name=_('country'), + verbose_name=_("country"), choices=Country(), default=Country.pl.id, ) stocktaking_enabled = models.BooleanField(default=False) """Used for distinguishing the origin of the object by region""" + class Permissions: has_access = has_region @@ -50,7 +51,9 @@ def object_has_region(user): class Regionalizable(PermissionsForObjectMixin): - region = models.ForeignKey(Region, blank=False, null=False, on_delete=models.CASCADE) + region = models.ForeignKey( + Region, blank=False, null=False, on_delete=models.CASCADE + ) class Meta: abstract = True @@ -64,14 +67,10 @@ class Team(AdminAbsoluteUrlMixin, NamedMixin): class RalphUser( - PermByFieldMixin, - AbstractUser, - AdminAbsoluteUrlMixin, - AutocompleteTooltipMixin + PermByFieldMixin, AbstractUser, AdminAbsoluteUrlMixin, AutocompleteTooltipMixin ): - country = models.PositiveIntegerField( - verbose_name=_('country'), + verbose_name=_("country"), choices=Country(), default=Country.pl.id, ) @@ -81,65 +80,70 @@ class RalphUser( blank=True, ) company = models.CharField( - verbose_name=_('company'), + verbose_name=_("company"), max_length=64, blank=True, ) employee_id = models.CharField( - verbose_name=_('employee id'), + verbose_name=_("employee id"), max_length=64, blank=True, ) profit_center = models.CharField( - verbose_name=_('profit center'), + verbose_name=_("profit center"), max_length=1024, blank=True, ) cost_center = models.CharField( - verbose_name=_('cost center'), + verbose_name=_("cost center"), max_length=1024, blank=True, ) department = models.CharField( - verbose_name=_('department'), + verbose_name=_("department"), max_length=128, blank=True, ) manager = models.CharField( - verbose_name=_('manager'), + verbose_name=_("manager"), max_length=1024, blank=True, ) location = models.CharField( - verbose_name=_('location'), + verbose_name=_("location"), max_length=128, blank=True, ) segment = models.CharField( - verbose_name=_('segment'), + verbose_name=_("segment"), max_length=256, blank=True, ) - regions = models.ManyToManyField(Region, related_name='users', blank=True) - team = models.ForeignKey(Team, null=True, blank=True, on_delete=models.CASCADE, ) + regions = models.ManyToManyField(Region, related_name="users", blank=True) + team = models.ForeignKey( + Team, + null=True, + blank=True, + on_delete=models.CASCADE, + ) autocomplete_tooltip_fields = [ - 'employee_id', - 'company', - 'department', - 'manager', - 'profit_center', - 'cost_center' + "employee_id", + "company", + "department", + "manager", + "profit_center", + "cost_center", ] autocomplete_words_split = True class Meta(AbstractUser.Meta): - swappable = 'AUTH_USER_MODEL' + swappable = "AUTH_USER_MODEL" def __str__(self): full_name = self.get_full_name() if full_name: - return '{} ({})'.format(full_name, self.username) + return "{} ({})".format(full_name, self.username) return super().__str__() @property @@ -154,10 +158,8 @@ def regions_ids(self): """ Get region ids without additional SQL joins. """ - return self.regions.through.objects.filter( - ralphuser=self - ).values_list( - 'region_id', flat=True + return self.regions.through.objects.filter(ralphuser=self).values_list( + "region_id", flat=True ) def has_any_perms(self, perms, obj=None): @@ -172,7 +174,7 @@ def save(self, *args, **kwargs): @property def autocomplete_str(self): - return '{} {}'.format(str(self), self.department) + return "{} {}".format(str(self), self.department) @property def permissions_hash(self): @@ -181,7 +183,7 @@ def permissions_hash(self): Hash for caching is calculated from user ID and its permissions. """ perms_set = frozenset(self.get_all_permissions()) - key = ':'.join((str(self.id), str(hash(perms_set)))) + key = ":".join((str(self.id), str(hash(perms_set)))) return hashlib.md5(force_bytes(key)).hexdigest() diff --git a/src/ralph/accounts/tests/factories.py b/src/ralph/accounts/tests/factories.py index 7527be81d0..dff99d765c 100644 --- a/src/ralph/accounts/tests/factories.py +++ b/src/ralph/accounts/tests/factories.py @@ -7,33 +7,30 @@ class RegionFactory(DjangoModelFactory): - - name = factory.Iterator(['pl', 'de', 'ua']) + name = factory.Iterator(["pl", "de", "ua"]) class Meta: model = Region - django_get_or_create = ['name'] + django_get_or_create = ["name"] class GroupFactory(DjangoModelFactory): - - name = factory.Iterator(['DBA', 'sysadmins', 'devops']) + name = factory.Iterator(["DBA", "sysadmins", "devops"]) class Meta: model = Group - django_get_or_create = ['name'] + django_get_or_create = ["name"] class UserFactory(DjangoModelFactory): - - username = factory.Faker('user_name') - first_name = factory.Faker('first_name') - last_name = factory.Faker('last_name') + username = factory.Faker("user_name") + first_name = factory.Faker("first_name") + last_name = factory.Faker("last_name") is_active = True class Meta: model = RalphUser - django_get_or_create = ['username'] + django_get_or_create = ["username"] @factory.post_generation def groups(self, create, extracted, **kwargs): @@ -49,8 +46,8 @@ def groups(self, create, extracted, **kwargs): class TeamFactory(DjangoModelFactory): - name = factory.Iterator(['DBA', 'sysadmins', 'devops']) + name = factory.Iterator(["DBA", "sysadmins", "devops"]) class Meta: model = Team - django_get_or_create = ['name'] + django_get_or_create = ["name"] diff --git a/src/ralph/accounts/tests/tests.py b/src/ralph/accounts/tests/tests.py index 48295d64c4..9e1bb9f641 100644 --- a/src/ralph/accounts/tests/tests.py +++ b/src/ralph/accounts/tests/tests.py @@ -10,20 +10,14 @@ from rest_framework import status from ralph.accounts.ldap import manager_country_attribute_populate -from ralph.accounts.management.commands.ldap_sync import ( - _truncate, - ldap_module_exists -) +from ralph.accounts.management.commands.ldap_sync import _truncate, ldap_module_exists from ralph.accounts.models import RalphUser, Region from ralph.api.tests._base import RalphAPITestCase from ralph.assets.tests.factories import ( BackOfficeAssetModelFactory, - ServiceEnvironmentFactory -) -from ralph.back_office.tests.factories import ( - BackOfficeAssetFactory, - WarehouseFactory + ServiceEnvironmentFactory, ) +from ralph.back_office.tests.factories import BackOfficeAssetFactory, WarehouseFactory from ralph.licences.models import LicenceUser from ralph.licences.tests.factories import LicenceFactory from ralph.tests import factories @@ -34,138 +28,124 @@ @unittest.skipIf(NO_LDAP_MODULE, "'ldap' module is not installed") class LdapSyncTest(TestCase): - def test_long_surname_is_truncated(self): - too_long_surname = 'long-surname' * 50 - ldap_dict = {'sn': [too_long_surname]} + too_long_surname = "long-surname" * 50 + ldap_dict = {"sn": [too_long_surname]} default_django_surname_length = 150 - _truncate('sn', 'last_name', ldap_dict) + _truncate("sn", "last_name", ldap_dict) self.assertEqual( - ldap_dict['sn'], - [too_long_surname[:default_django_surname_length]] + ldap_dict["sn"], [too_long_surname[:default_django_surname_length]] ) def test_short_surname_stays_unmodified(self): - short_surname = 'short-surname' - ldap_dict = {'sn': [short_surname]} - _truncate('sn', 'last_name', ldap_dict) - self.assertEqual(ldap_dict['sn'], [short_surname]) + short_surname = "short-surname" + ldap_dict = {"sn": [short_surname]} + _truncate("sn", "last_name", ldap_dict) + self.assertEqual(ldap_dict["sn"], [short_surname]) def test_truncate_works_when_no_sn(self): ldap_dict = {} - _truncate('sn', 'last_name', ldap_dict) + _truncate("sn", "last_name", ldap_dict) @unittest.skipIf(NO_LDAP_MODULE, "'ldap' module is not installed") class LdapPopulateTest(TestCase): - def _get_mocked_ldap_user(self, attrs): class MockedLdapUser(object): @property def attrs(self): return attrs + return MockedLdapUser() def test_manager_country_attribute_populate_country(self): - ldap_attr = 'c' - override_settings = {'country': ldap_attr} + ldap_attr = "c" + override_settings = {"country": ldap_attr} user = factories.UserFactory() - faked_ldap_user = self._get_mocked_ldap_user({ - ldap_attr: ['XXX'] - }) + faked_ldap_user = self._get_mocked_ldap_user({ldap_attr: ["XXX"]}) with self.settings(AUTH_LDAP_USER_ATTR_MAP=override_settings): - manager_country_attribute_populate( - None, user, faked_ldap_user - ) + manager_country_attribute_populate(None, user, faked_ldap_user) self.assertEqual(user.country, None) def test_manager_country_attribute_populate_unicode_in_manager(self): - ldap_attr = 'manager' - override_settings = {'manager': ldap_attr} - manager_names = [str('ŻółcieÅ„'), str('John Smith')] + ldap_attr = "manager" + override_settings = {"manager": ldap_attr} + manager_names = [str("ŻółcieÅ„"), str("John Smith")] user = factories.UserFactory() for manager_name in manager_names: - faked_ldap_user = self._get_mocked_ldap_user({ - ldap_attr: ['CN={},OU=XXX,DC=group'.format(manager_name)] - }) + faked_ldap_user = self._get_mocked_ldap_user( + {ldap_attr: ["CN={},OU=XXX,DC=group".format(manager_name)]} + ) with self.settings(AUTH_LDAP_USER_ATTR_MAP=override_settings): - manager_country_attribute_populate( - None, user, faked_ldap_user - ) + manager_country_attribute_populate(None, user, faked_ldap_user) self.assertEqual(user.manager, manager_name) self.assertTrue(isinstance(user.manager, str)) class RalphUserAPITests(RalphAPITestCase): def test_get_user_list(self): - url = reverse('ralphuser-list') - response = self.client.get(url, format='json') + url = reverse("ralphuser-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], RalphUser.objects.count()) + self.assertEqual(response.data["count"], RalphUser.objects.count()) def test_get_user_details(self): - region = Region.objects.create(name='EU') + region = Region.objects.create(name="EU") self.user1.regions.add(region) bo_asset_as_user = BackOfficeAssetFactory(user=self.user1) bo_asset_as_owner = BackOfficeAssetFactory(owner=self.user1) licence = LicenceFactory() LicenceUser.objects.create(licence=licence, user=self.user1) - url = reverse('ralphuser-detail', args=(self.user1.id,)) - response = self.client.get(url, format='json') + url = reverse("ralphuser-detail", args=(self.user1.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['username'], self.user1.username) - self.assertEqual(response.data['first_name'], self.user1.first_name) - self.assertEqual(response.data['last_name'], self.user1.last_name) - self.assertEqual(response.data['regions'][0]['id'], region.id) + self.assertEqual(response.data["username"], self.user1.username) + self.assertEqual(response.data["first_name"], self.user1.first_name) + self.assertEqual(response.data["last_name"], self.user1.last_name) + self.assertEqual(response.data["regions"][0]["id"], region.id) self.assertEqual( - response.data['assets_as_owner'][0]['id'], bo_asset_as_owner.id - ) - self.assertEqual( - response.data['assets_as_user'][0]['id'], bo_asset_as_user.id - ) - self.assertEqual( - response.data['licences'][0]['licence']['id'], licence.id + response.data["assets_as_owner"][0]["id"], bo_asset_as_owner.id ) + self.assertEqual(response.data["assets_as_user"][0]["id"], bo_asset_as_user.id) + self.assertEqual(response.data["licences"][0]["licence"]["id"], licence.id) def test_create_user_should_raise_method_not_allowed(self): - url = reverse('ralphuser-list') + url = reverse("ralphuser-list") data = { - 'username': 'ralph', - 'first_name': 'John', - 'last_name': 'Snow', + "username": "ralph", + "first_name": "John", + "last_name": "Snow", } - response = self.client.post(url, data, format='json') - self.assertEqual( - response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED - ) + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) def test_patch_user(self): - region = Region.objects.create(name='EU') - url = reverse('ralphuser-detail', args=(self.user1.id,)) + region = Region.objects.create(name="EU") + url = reverse("ralphuser-detail", args=(self.user1.id,)) data = { - 'first_name': 'Ralph', - 'last_name': 'Django', - 'regions': [region.id], + "first_name": "Ralph", + "last_name": "Django", + "regions": [region.id], } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.user1.refresh_from_db() - self.assertEqual(self.user1.first_name, 'Ralph') - self.assertEqual(self.user1.last_name, 'Django') + self.assertEqual(self.user1.first_name, "Ralph") + self.assertEqual(self.user1.last_name, "Django") self.assertIn(region, self.user1.regions.all()) def test_patch_user_when_user_is_not_superuser_should_raise_forbidden(self): - region = Region.objects.create(name='EU') + region = Region.objects.create(name="EU") self.client.force_authenticate(self.user2) - url = reverse('ralphuser-detail', args=(self.user1.id,)) + url = reverse("ralphuser-detail", args=(self.user1.id,)) data = { - 'first_name': 'Ralph', - 'last_name': 'Django', - 'regions': [region.id], + "first_name": "Ralph", + "last_name": "Django", + "regions": [region.id], } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) @@ -187,14 +167,14 @@ def setUp(self): self.asset.save() self.base_tag = settings.INVENTORY_TAG - if self.asset.warehouse.stocktaking_tag_suffix != '': - self.base_tag = '{prefix}-{warehouse}'.format( + if self.asset.warehouse.stocktaking_tag_suffix != "": + self.base_tag = "{prefix}-{warehouse}".format( prefix=self.base_tag, warehouse=self.asset.warehouse.stocktaking_tag_suffix, ) self.date_tag = None if settings.INVENTORY_TAG_APPEND_DATE: - self.date_tag = '{base}_{date}'.format( + self.date_tag = "{base}_{date}".format( base=self.base_tag, date=date.today().isoformat(), ) @@ -207,12 +187,9 @@ def setUp(self): def test_tag_asset(self): self.assertTrue(self.login_as_user(self.user1)) response = self.client.post( - reverse('inventory_tag'), - { - 'asset_id': self.asset.id, - 'confirm_button': 'Yes', - 'answer': 'yes' - }, follow=True + reverse("inventory_tag"), + {"asset_id": self.asset.id, "confirm_button": "Yes", "answer": "yes"}, + follow=True, ) self.assertEqual(response.status_code, 200) @@ -222,12 +199,9 @@ def test_tag_asset(self): def test_ownership_verification(self): self.assertTrue(self.login_as_user(self.user2)) response = self.client.post( - reverse('inventory_tag'), - { - 'asset_id': self.asset.id, - 'confirm_button': 'Yes', - 'answer': 'yes' - }, follow=True + reverse("inventory_tag"), + {"asset_id": self.asset.id, "confirm_button": "Yes", "answer": "yes"}, + follow=True, ) self.assertEqual(response.status_code, 403) @@ -241,24 +215,18 @@ def setUp(self): def test_change_permission_is_required_to_change_user_password(self): def make_request(): - url = reverse( - 'admin:auth_user_password_change', args=(self.admin.pk,) - ) + url = reverse("admin:auth_user_password_change", args=(self.admin.pk,)) return self.client.post( - url, - { - 'password1': new_password, - 'password2': new_password - } + url, {"password1": new_password, "password2": new_password} ) - new_password = 'password123' - perm = Permission.objects.get(codename='view_ralphuser') + new_password = "password123" + perm = Permission.objects.get(codename="view_ralphuser") self.user.user_permissions.add(perm) response = make_request() self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - perm = Permission.objects.get(codename='change_ralphuser') + perm = Permission.objects.get(codename="change_ralphuser") self.user.user_permissions.add(perm) response = make_request() self.assertEqual(response.status_code, status.HTTP_302_FOUND) diff --git a/src/ralph/accounts/urls.py b/src/ralph/accounts/urls.py index 8e48361157..4b5c5441ef 100644 --- a/src/ralph/accounts/urls.py +++ b/src/ralph/accounts/urls.py @@ -5,29 +5,28 @@ CurrentUserInfoView, InventoryTagConfirmationView, InventoryTagView, - UserProfileView + UserProfileView, ) urlpatterns = [ url( - r'^user_profile/?$', + r"^user_profile/?$", login_required(UserProfileView.as_view()), - name='user_profile' + name="user_profile", ), url( - r'^my_equipment/?$', + r"^my_equipment/?$", login_required(CurrentUserInfoView.as_view()), - name='current_user_info' + name="current_user_info", ), url( - r'^my_equipment/inventory_tag/' - r'(?P[0-9]+)/(?Pyes|no)/$', + r"^my_equipment/inventory_tag/" r"(?P[0-9]+)/(?Pyes|no)/$", login_required(InventoryTagConfirmationView.as_view()), - name='inventory_tag_confirmation' + name="inventory_tag_confirmation", ), url( - r'^my_equipment/inventory_tag/$', + r"^my_equipment/inventory_tag/$", login_required(InventoryTagView.as_view()), - name='inventory_tag' + name="inventory_tag", ), ] diff --git a/src/ralph/accounts/views.py b/src/ralph/accounts/views.py index 94cbe2fb70..f3b76158aa 100644 --- a/src/ralph/accounts/views.py +++ b/src/ralph/accounts/views.py @@ -14,7 +14,7 @@ AssetList, AssignedLicenceList, AssignedSimcardsList, - UserInfoMixin + UserInfoMixin, ) from ralph.accounts.helpers import ( ACCEPTANCE_LOAN_TRANSITION_ID, @@ -24,7 +24,7 @@ get_assets_to_accept, get_assets_to_accept_loan, get_loan_acceptance_url, - loan_transition_exists + loan_transition_exists, ) from ralph.admin.mixins import RalphBaseTemplateView, RalphTemplateView from ralph.back_office.models import BackOfficeAsset @@ -32,47 +32,50 @@ class UserProfileView(RalphTemplateView): - template_name = 'ralphuser/user_profile.html' + template_name = "ralphuser/user_profile.html" class MyEquipmentAssetList(AssetList): def user_licence(self, item): - licences = BaseObjectLicence.objects.filter( - base_object=item.id - ).select_related('licence', 'licence__software') + licences = BaseObjectLicence.objects.filter(base_object=item.id).select_related( + "licence", "licence__software" + ) if licences: result = [ '  {} ({})'.format( # noqa bo_licence.licence.software.name, bo_licence.licence.niw, - ) for bo_licence in licences + ) + for bo_licence in licences ] - return ['
'.join(result)] + return ["
".join(result)] else: return [] class InventoryTagConfirmationView(RalphBaseTemplateView): - template_name = 'ralphuser/inventory_tag_confirmation.html' + template_name = "ralphuser/inventory_tag_confirmation.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) asset_fields = [ - ('barcode', _('Barcode / Inventory Number')), - 'model__category__name', 'model__manufacturer__name', - 'model__name', ('sn', _('Serial Number')) + ("barcode", _("Barcode / Inventory Number")), + "model__category__name", + "model__manufacturer__name", + "model__name", + ("sn", _("Serial Number")), ] - context['asset_details'] = MyEquipmentAssetList( - BackOfficeAsset.objects.filter(id=self.kwargs['asset_id']), + context["asset_details"] = MyEquipmentAssetList( + BackOfficeAsset.objects.filter(id=self.kwargs["asset_id"]), asset_fields, - request=self.request + request=self.request, ) return context class InventoryTagView(View): - http_method_names = ['post'] + http_method_names = ["post"] @staticmethod def _add_tags(request, asset, tags): @@ -80,28 +83,27 @@ def _add_tags(request, asset, tags): with reversion.create_revision(): asset.save() reversion.set_user(request.user) - reversion.set_comment('Added tags {}'.format(', '.join(tags))) + reversion.set_comment("Added tags {}".format(", ".join(tags))) def _post_no(self, request, asset): tags = [settings.INVENTORY_TAG_MISSING] - missing_asset_info = 'Please contact person responsible ' \ - 'for asset management' + missing_asset_info = "Please contact person responsible " "for asset management" if settings.MISSING_ASSET_REPORT_URL is not None: - missing_asset_info += '\n' + settings.MISSING_ASSET_REPORT_URL + missing_asset_info += "\n" + settings.MISSING_ASSET_REPORT_URL self._add_tags(request, asset, tags) messages.info(request, _(missing_asset_info)) def _post_yes(self, request, asset): base_tag = settings.INVENTORY_TAG - if asset.warehouse.stocktaking_tag_suffix != '': - base_tag = '{prefix}-{warehouse}'.format( + if asset.warehouse.stocktaking_tag_suffix != "": + base_tag = "{prefix}-{warehouse}".format( prefix=base_tag, warehouse=asset.warehouse.stocktaking_tag_suffix, ) date_tag = None if settings.INVENTORY_TAG_APPEND_DATE: - date_tag = '{base}_{date}'.format( + date_tag = "{base}_{date}".format( base=base_tag, date=date.today().isoformat(), ) @@ -113,36 +115,32 @@ def _post_yes(self, request, asset): ] self._add_tags(request, asset, tags) - messages.success(request, _('Successfully tagged asset')) + messages.success(request, _("Successfully tagged asset")) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['answer'] = kwargs['answer'] + context["answer"] = kwargs["answer"] return context def post(self, request, *args, **kwargs): - asset = get_object_or_404(BackOfficeAsset, id=request.POST['asset_id']) - if ( - asset.user_id != request.user.id or - not ( - asset.warehouse.stocktaking_enabled or - asset.region.stocktaking_enabled - ) + asset = get_object_or_404(BackOfficeAsset, id=request.POST["asset_id"]) + if asset.user_id != request.user.id or not ( + asset.warehouse.stocktaking_enabled or asset.region.stocktaking_enabled ): return HttpResponseForbidden() - if request.POST['answer'] == 'yes': + if request.POST["answer"] == "yes": self._post_yes(request, asset) - elif request.POST['answer'] == 'no': + elif request.POST["answer"] == "no": self._post_no(request, asset) - return HttpResponseRedirect(reverse('current_user_info')) + return HttpResponseRedirect(reverse("current_user_info")) class _AcceptanceProcessByCurrentUserMixin(object): def post(self, request, *args, **kwargs): - action = request.POST['action'] - if action == 'accept': + action = request.POST["action"] + if action == "accept": acceptance_url = get_acceptance_url(request.user) else: acceptance_url = get_loan_acceptance_url(request.user) @@ -152,12 +150,12 @@ def post(self, request, *args, **kwargs): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['acceptance_transition_id'] = ACCEPTANCE_TRANSITION_ID - context['acceptance_transition_exists'] = acceptance_transition_exists() # noqa: E501 - context['assets_to_accept'] = get_assets_to_accept(self.request.user) - context['loan_transition_id'] = ACCEPTANCE_LOAN_TRANSITION_ID - context['loan_transition_exists'] = loan_transition_exists() - context['assets_to_loan'] = get_assets_to_accept_loan(self.request.user) # noqa: E501 + context["acceptance_transition_id"] = ACCEPTANCE_TRANSITION_ID + context["acceptance_transition_exists"] = acceptance_transition_exists() # noqa: E501 + context["assets_to_accept"] = get_assets_to_accept(self.request.user) + context["loan_transition_id"] = ACCEPTANCE_LOAN_TRANSITION_ID + context["loan_transition_exists"] = loan_transition_exists() + context["assets_to_loan"] = get_assets_to_accept_loan(self.request.user) # noqa: E501 return context @@ -173,51 +171,54 @@ class _DummyMixin(object): class CurrentUserInfoView( - AcceptAssetsForCurrentUserMixin, - UserInfoMixin, - RalphBaseTemplateView + AcceptAssetsForCurrentUserMixin, UserInfoMixin, RalphBaseTemplateView ): - template_name = 'ralphuser/my_equipment.html' + template_name = "ralphuser/my_equipment.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['my_equipment_links'] = self.get_links() + context["my_equipment_links"] = self.get_links() asset_fields = [ - 'user', ('barcode', _('Barcode / Inventory Number')), - 'model__category__name', 'model__manufacturer__name', - 'model__name', ('sn', _('Serial Number')), 'invoice_date', 'status', + "user", + ("barcode", _("Barcode / Inventory Number")), + "model__category__name", + "model__manufacturer__name", + "model__name", + ("sn", _("Serial Number")), + "invoice_date", + "status", ] if settings.MY_EQUIPMENT_SHOW_BUYOUT_DATE: - asset_fields += ['buyout_date'] + asset_fields += ["buyout_date"] - context['asset_list'] = MyEquipmentAssetList( + context["asset_list"] = MyEquipmentAssetList( self.get_asset_queryset(), asset_fields, - ['user_licence'], + ["user_licence"], request=self.request, ) - context['licence_list'] = AssignedLicenceList( + context["licence_list"] = AssignedLicenceList( self.get_licence_queryset(), [ - ('niw', _('Inventory Number')), 'manufacturer', - 'software__name', 'licence_type', 'sn', - 'valid_thru' + ("niw", _("Inventory Number")), + "manufacturer", + "software__name", + "licence_type", + "sn", + "valid_thru", ], request=self.request, ) - context['managing_devices_moved_info'] = ( - settings.MANAGING_DEVICES_MOVED_INFO - ) + context["managing_devices_moved_info"] = settings.MANAGING_DEVICES_MOVED_INFO - context['simcard_list'] = AssignedSimcardsList( + context["simcard_list"] = AssignedSimcardsList( self.get_simcard_queryset(), [ - ('phone_number', _('Phone Number')), - ('card_number', _('Card Number')), - ('pin1', _('PIN 1')) - + ("phone_number", _("Phone Number")), + ("card_number", _("Card Number")), + ("pin1", _("PIN 1")), ], request=self.request, ) @@ -226,17 +227,12 @@ def get_context_data(self, **kwargs): def get_links(self): result = [] - links = getattr( - settings, 'MY_EQUIPMENT_LINKS', [] - ) + links = getattr(settings, "MY_EQUIPMENT_LINKS", []) kwargs = { - 'username': self.request.user.username, + "username": self.request.user.username, } for link in links: - result.append({ - 'url': link['url'].format(**kwargs), - 'name': link['name'] - }) + result.append({"url": link["url"].format(**kwargs), "name": link["name"]}) return result def get_user(self): @@ -244,4 +240,4 @@ def get_user(self): def get_asset_queryset(self): qs = super().get_asset_queryset() - return qs.select_related('user') + return qs.select_related("user") diff --git a/src/ralph/admin/__init__.py b/src/ralph/admin/__init__.py index ac25e79c80..ae419a6098 100644 --- a/src/ralph/admin/__init__.py +++ b/src/ralph/admin/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.admin.apps.RalphAdminConfig' +default_app_config = "ralph.admin.apps.RalphAdminConfig" diff --git a/src/ralph/admin/apps.py b/src/ralph/admin/apps.py index e5b701d881..e11517165e 100644 --- a/src/ralph/admin/apps.py +++ b/src/ralph/admin/apps.py @@ -4,11 +4,12 @@ class RalphAdminConfig(RalphAppConfig): - name = 'ralph.admin' - label = 'ralph_admin' - verbose_name = 'Ralph Admin' + name = "ralph.admin" + label = "ralph_admin" + verbose_name = "Ralph Admin" def ready(self): from ralph.admin.filters import register_custom_filters + register_custom_filters() super().ready() diff --git a/src/ralph/admin/autocomplete.py b/src/ralph/admin/autocomplete.py index 7b0b7783b4..f8e280c887 100644 --- a/src/ralph/admin/autocomplete.py +++ b/src/ralph/admin/autocomplete.py @@ -14,16 +14,16 @@ from ralph.admin.helpers import ( get_admin_url, get_field_by_relation_path, - get_value_by_relation_path + get_value_by_relation_path, ) from ralph.admin.sites import ralph_site from ralph.lib.permissions.models import PermissionsForObjectMixin -AUTOCOMPLETE_EMPTY_VALUE = '0' +AUTOCOMPLETE_EMPTY_VALUE = "0" AUTOCOMPLETE_EMPTY_LABEL = 'empty' -QUERY_PARAM = 'q' -DETAIL_PARAM = 'pk' -QUERY_REGEX = re.compile(r'[.| ]') +QUERY_PARAM = "q" +DETAIL_PARAM = "pk" +QUERY_REGEX = re.compile(r"[.| ]") logger = logging.getLogger(__name__) @@ -31,20 +31,25 @@ def get_results(queryset, can_edit, prepend_empty=False): results = [] if prepend_empty: - results.append({ - 'pk': AUTOCOMPLETE_EMPTY_VALUE, - '__str__': AUTOCOMPLETE_EMPTY_LABEL, - }) - results.extend([ - { - 'pk': obj.pk, - '__str__': getattr(obj, 'autocomplete_str', str(obj)), - 'edit_url': '{}?_popup=1'.format( - get_admin_url(obj, 'change') - ) if can_edit else None, - 'tooltip': getattr(obj, 'autocomplete_tooltip', None) - } for obj in queryset - ]) + results.append( + { + "pk": AUTOCOMPLETE_EMPTY_VALUE, + "__str__": AUTOCOMPLETE_EMPTY_LABEL, + } + ) + results.extend( + [ + { + "pk": obj.pk, + "__str__": getattr(obj, "autocomplete_str", str(obj)), + "edit_url": "{}?_popup=1".format(get_admin_url(obj, "change")) + if can_edit + else None, + "tooltip": getattr(obj, "autocomplete_tooltip", None), + } + for obj in queryset + ] + ) return results @@ -52,6 +57,7 @@ class JsonViewMixin(object): """ A mixin that can be used to render a JSON response. """ + def render_to_json_response(self, context, **response_kwargs): """ Returns a JSON response, transforming 'context' to make the payload. @@ -60,20 +66,20 @@ def render_to_json_response(self, context, **response_kwargs): class AutocompleteTooltipMixin(object): - autocomplete_tooltip_fields = [] @property def autocomplete_tooltip(self): - empty_element = '' + empty_element = "" tooltip = [] for field in self.autocomplete_tooltip_fields: try: model_field = get_field_by_relation_path(self, field) except FieldDoesNotExist: logger.warning( - 'Autocomplete tooltip field %s not found for %s', - field, self._meta.model_name + "Autocomplete tooltip field %s not found for %s", + field, + self._meta.model_name, ) continue value = get_value_by_relation_path(self, field) @@ -81,18 +87,17 @@ def autocomplete_tooltip(self): value = model_field.choices.name_from_id(value) label = str(model_field.verbose_name) if isinstance(value, Manager): - value = ', '.join(map(str, value.all())) - tooltip.append('{}: {}'.format( - label.capitalize(), value or empty_element - )) - return '\n'.join(tooltip) + value = ", ".join(map(str, value.all())) + tooltip.append("{}: {}".format(label.capitalize(), value or empty_element)) + return "\n".join(tooltip) class SuggestView(JsonViewMixin, View): """ Base class for list and detail view. """ - http_method_names = ['get'] + + http_method_names = ["get"] def get_results(self, user, can_edit, prepend_empty=False): return get_results(self.get_queryset(user), can_edit, prepend_empty) @@ -103,17 +108,16 @@ def get(self, request, *args, **kwargs): """ # TODO # Add in the future redirected to the model that is being edited - can_edit = ralph_site._registry[self.model].has_change_permission( - self.request - ) + can_edit = ralph_site._registry[self.model].has_change_permission(self.request) results = self.get_results(request.user, can_edit) - return self.render_to_json_response({'results': results}) + return self.render_to_json_response({"results": results}) class AjaxAutocompleteMixin(object): """ This mixin added new endpoint to admin's urls for autocomplete mechanism. """ + def get_autocomplete_queryset(self): return self.model._default_manager.all() @@ -129,7 +133,7 @@ def dispatch(self, request, *args, **kwargs): self.pk = request.GET.get(DETAIL_PARAM, None) if not self.pk: return HttpResponseBadRequest() - self.values = self.pk.split(',') + self.values = self.pk.split(",") return super().dispatch(request, *args, **kwargs) def get_results(self, user, can_edit): @@ -138,8 +142,7 @@ def get_results(self, user, can_edit): return results def get_queryset(self, user): - queryset = self.model._default_manager.filter( - pk__in=self.values) + queryset = self.model._default_manager.filter(pk__in=self.values) if issubclass(self.model, PermissionsForObjectMixin): queryset = self.model._get_objects_for_user(user, queryset) if self.values != [self.empty_value] and not queryset.exists(): @@ -149,9 +152,9 @@ def get_queryset(self, user): params = outer_model._meta.app_label, outer_model._meta.model_name my_urls = [ url( - r'^autocomplete/details/$', + r"^autocomplete/details/$", Detail.as_view(), - name='{}_{}_autocomplete_details'.format(*params) + name="{}_{}_autocomplete_details".format(*params), ), ] return my_urls + urls @@ -164,11 +167,11 @@ class AutocompleteList(SuggestView): def dispatch(self, request, *args, **kwargs): try: - model = apps.get_model(kwargs['app'], kwargs['model']) + model = apps.get_model(kwargs["app"], kwargs["model"]) except LookupError: - return HttpResponseBadRequest('Model not found') + return HttpResponseBadRequest("Model not found") - self.field = model._meta.get_field(kwargs['field']) + self.field = model._meta.get_field(kwargs["field"]) self.model = self.field.remote_field.model self.query = request.GET.get(QUERY_PARAM, None) if not self.query: @@ -187,27 +190,22 @@ def get_query_filters(self, queryset, query, search_fields): Returns: Django queryset """ - split_by_words = getattr(self.model, 'autocomplete_words_split', False) + split_by_words = getattr(self.model, "autocomplete_words_split", False) if split_by_words: for value in QUERY_REGEX.split(query): if value: query_filters = [ - Q(**{'{}__icontains'.format(field): value}) + Q(**{"{}__icontains".format(field): value}) for field in search_fields ] if query_filters: - queryset = queryset.filter( - reduce(operator.or_, query_filters) - ) + queryset = queryset.filter(reduce(operator.or_, query_filters)) else: query_filters = [ - Q(**{'{}__icontains'.format(field): query}) - for field in search_fields + Q(**{"{}__icontains".format(field): query}) for field in search_fields ] if query_filters: - queryset = queryset.filter( - reduce(operator.or_, query_filters) - ) + queryset = queryset.filter(reduce(operator.or_, query_filters)) return queryset def get_base_ids(self, model, value): @@ -220,32 +218,24 @@ def get_base_ids(self, model, value): return [] queryset = getattr( - model, - 'get_autocomplete_queryset', - model._default_manager.all + model, "get_autocomplete_queryset", model._default_manager.all )() if issubclass(model, PermissionsForObjectMixin): - queryset = model._get_objects_for_user( - self.request.user, queryset - ) + queryset = model._get_objects_for_user(self.request.user, queryset) queryset = self.get_query_filters(queryset, value, search_fields) - return queryset[:self.limit].values_list('pk', flat=True) + return queryset[: self.limit].values_list("pk", flat=True) def get_results(self, user, can_edit): - prepend_empty = self.request.GET.get('prepend-empty', 0) == 'true' + prepend_empty = self.request.GET.get("prepend-empty", 0) == "true" results = super().get_results(user, can_edit, prepend_empty) return results def get_queryset(self, user): search_fields = ralph_site._registry[self.model].search_fields queryset = getattr( - self.model, - 'get_autocomplete_queryset', - self.model._default_manager.all + self.model, "get_autocomplete_queryset", self.model._default_manager.all )() - polymorphic_descendants = getattr( - self.model, '_polymorphic_descendants', [] - ) + polymorphic_descendants = getattr(self.model, "_polymorphic_descendants", []) limit_choices = self.field.get_limit_choices_to() if limit_choices: queryset = queryset.filter(**limit_choices) @@ -257,19 +247,17 @@ def get_queryset(self, user): if polymorphic_descendants: id_list = [] for related_model in polymorphic_descendants: - id_list.extend(self.get_base_ids( - related_model, - self.query, - )) + id_list.extend( + self.get_base_ids( + related_model, + self.query, + ) + ) queryset = queryset.filter(pk__in=id_list) else: if self.query: - queryset = self.get_query_filters( - queryset, self.query, search_fields - ) + queryset = self.get_query_filters(queryset, self.query, search_fields) if issubclass(self.model, PermissionsForObjectMixin): - queryset = self.model._get_objects_for_user( - user, queryset - ) + queryset = self.model._get_objects_for_user(user, queryset) queryset = queryset.distinct() - return queryset[:self.limit] + return queryset[: self.limit] diff --git a/src/ralph/admin/autocomplete_urls.py b/src/ralph/admin/autocomplete_urls.py index 0a3aa0cee2..68ef23446f 100644 --- a/src/ralph/admin/autocomplete_urls.py +++ b/src/ralph/admin/autocomplete_urls.py @@ -7,8 +7,8 @@ urlpatterns = [ url( - r'^(?P\w+)/(?P\w+)/(?P\w+)/autocomplete$', + r"^(?P\w+)/(?P\w+)/(?P\w+)/autocomplete$", login_required(ralph_site.admin_view(AutocompleteList.as_view())), - name='autocomplete-list' + name="autocomplete-list", ), ] diff --git a/src/ralph/admin/decorators.py b/src/ralph/admin/decorators.py index 3795fbe392..4377a51983 100644 --- a/src/ralph/admin/decorators.py +++ b/src/ralph/admin/decorators.py @@ -6,12 +6,7 @@ from django.db.models import Model from ralph.admin.sites import ralph_site -from ralph.admin.views.extra import ( - CHANGE, - LIST, - RalphExtraViewMixin, - VIEW_TYPES -) +from ralph.admin.views.extra import CHANGE, LIST, RalphExtraViewMixin, VIEW_TYPES register = partial(django_register, site=ralph_site) @@ -23,20 +18,20 @@ class WrongViewClassError(Exception): class register_extra_view(object): # noqa def __init__(self, target_model): if Model not in target_model.__mro__: - raise TypeError('Model must be a inherited from models.Model.') + raise TypeError("Model must be a inherited from models.Model.") self.target_model = target_model def __call__(self, view): admin_model = ralph_site._registry[self.target_model] if not issubclass(view, RalphExtraViewMixin): raise ValueError( - 'The view must be inherited from RalphDetailView ' - 'or RalphListView' + "The view must be inherited from RalphDetailView " "or RalphListView" ) if view._type not in VIEW_TYPES: raise ValueError( - 'The view._type must be a one of ' - 'defined choices ({}).'.format(', '.join(VIEW_TYPES)) + "The view._type must be a one of " "defined choices ({}).".format( + ", ".join(VIEW_TYPES) + ) ) if view._type == LIST: admin_model.list_views = admin_model.list_views or [] @@ -51,7 +46,7 @@ def __call__(self, view): class register_extra_filter(object): # noqa def __init__(self, target_model, target_field_name): if not issubclass(target_model, Model): - raise TypeError('Model must be a inherited from models.Model.') + raise TypeError("Model must be a inherited from models.Model.") self.target_model = target_model self.target_field_name = target_field_name @@ -60,9 +55,7 @@ def __call__(self, admin_filter): admin_model = ralph_site._registry[self.target_model] if not issubclass(admin_filter, ListFilter): - raise ValueError( - 'The filter must be inherited from ListFilter.' - ) + raise ValueError("The filter must be inherited from ListFilter.") admin_model.list_filter = admin_model.list_filter or [] admin_model.list_filter.append((self.target_field_name, admin_filter)) diff --git a/src/ralph/admin/fields.py b/src/ralph/admin/fields.py index 4879598bf1..d57222b009 100644 --- a/src/ralph/admin/fields.py +++ b/src/ralph/admin/fields.py @@ -15,24 +15,22 @@ class MultilineField(forms.CharField): Validation: - separated values cannot duplicate each other, """ + widget = forms.Textarea - separators = r',|\n|\|' + separators = r",|\n|\|" def __init__(self, allow_duplicates=True, *args, **kwargs): self.allow_duplicates = allow_duplicates super().__init__(*args, **kwargs) def validate(self, values): - if not values and self.required: error_msg = _( "Field can't be empty. Please put the item OR items separated " "by new line or comma." ) - raise forms.ValidationError(error_msg, code='required') - non_empty_values = [ - item for item in values if str(item).strip() - ] + raise forms.ValidationError(error_msg, code="required") + non_empty_values = [item for item in values if str(item).strip()] if not self.allow_duplicates: has_duplicates = len(set(non_empty_values)) != len(non_empty_values) if has_duplicates: @@ -42,19 +40,18 @@ def to_python(self, value): items = [] if value: for item in re.split(self.separators, value): - items.append(item.strip(' \t\n\r')) + items.append(item.strip(" \t\n\r")) return items class IntegerMultilineField(MultilineField): - def to_python(self, value): result = super().to_python(value) try: return [int(i) for i in result] except ValueError: - raise ValidationError(_('Enter a valid number.')) + raise ValidationError(_("Enter a valid number.")) class MultivalueFormMixin(object): @@ -73,6 +70,7 @@ class MultivalueFormMixin(object): ,2 # valid , # invalid, because neither sn nor barcode was provided """ + multivalue_fields = [] one_of_mulitvalue_required = [] model = None @@ -87,12 +85,9 @@ def equal_count_validator(self, cleaned_data): if len(items_count_per_multi) > 1: for field in self.multivalue_fields: if field in cleaned_data: - msg = _(( - "Fields: %(fields)s " - "- require the same number of items") - ) % { - 'fields': ', '.join(self.multivalue_fields) - } + msg = _( + ("Fields: %(fields)s " "- require the same number of items") + ) % {"fields": ", ".join(self.multivalue_fields)} self.errors.setdefault(field, []).append(msg) def any_in_multivalues_validator(self, data): @@ -100,11 +95,12 @@ def any_in_multivalues_validator(self, data): Checks if each row has filled at least one field specified by one_of_mulitvalue_required. """ + def rows_of_required(): rows_of_required = [ - self.cleaned_data[field_name] for field_name in - self.one_of_mulitvalue_required if field_name in - self.cleaned_data + self.cleaned_data[field_name] + for field_name in self.one_of_mulitvalue_required + if field_name in self.cleaned_data ] for multivalues_row in zip(*rows_of_required): yield multivalues_row @@ -113,11 +109,9 @@ def rows_of_required(): for row_of_required in rows_of_required(): if not any(row_of_required): for field_name in self.one_of_mulitvalue_required: - errors = self._errors.setdefault( - field_name, ErrorList() - ) - msg = _('Fill at least on of %(v)s in each row') % { - 'v': ','.join(self.one_of_mulitvalue_required) + errors = self._errors.setdefault(field_name, ErrorList()) + msg = _("Fill at least on of %(v)s in each row") % { + "v": ",".join(self.one_of_mulitvalue_required) } errors.append(_(msg)) break @@ -132,18 +126,17 @@ def check_field_uniqueness(self, model, field_name, values): """ if not values: return - conditions = {'{}__in'.format(field_name): values} + conditions = {"{}__in".format(field_name): values} objs = model.objects.filter(**conditions) if objs: - if hasattr(model, 'get_absolute_url'): + if hasattr(model, "get_absolute_url"): url = '{}' - comma_items = ', '.join([ - url.format(obj.get_absolute_url(), obj.id) - for obj in objs - ]) + comma_items = ", ".join( + [url.format(obj.get_absolute_url(), obj.id) for obj in objs] + ) else: - comma_items = ', '.join([str(obj) for obj in objs]) - msg = _('Following items already exist: ') + comma_items + comma_items = ", ".join([str(obj) for obj in objs]) + msg = _("Following items already exist: ") + comma_items raise ValidationError(mark_safe(msg)) def check_uniqness(self, data): @@ -170,7 +163,7 @@ def extend_empty_fields_at_the_end(self, data): max_length = max(max_length, len(value)) for field in self.multivalue_fields: value = data.get(field, []) - data[field] = value + [''] * (max_length - len(value)) # None? + data[field] = value + [""] * (max_length - len(value)) # None? # remove empty lines while True: rows = list(zip(*[data[f] for f in self.multivalue_fields])) diff --git a/src/ralph/admin/filters.py b/src/ralph/admin/filters.py index 31136662bb..7d4b6c5310 100644 --- a/src/ralph/admin/filters.py +++ b/src/ralph/admin/filters.py @@ -26,8 +26,8 @@ from ralph.admin.helpers import get_field_by_relation_path from ralph.lib.mixins.fields import MACAddressField -SEARCH_OR_SEPARATORS_REGEX = re.compile(r'[;|]') -SEARCH_AND_SEPARATORS_REGEX = re.compile(r'[&]') +SEARCH_OR_SEPARATORS_REGEX = re.compile(r"[;|]") +SEARCH_AND_SEPARATORS_REGEX = re.compile(r"[&]") @lru_cache() @@ -42,10 +42,10 @@ def date_format_to_human(value): :param value: Date format example: %Y-%m """ maps = { - '%y': 'YY', - '%Y': 'YYYY', - '%m': 'MM', - '%d': 'DD', + "%y": "YY", + "%Y": "YYYY", + "%m": "MM", + "%d": "DD", } for k, v in maps.items(): value = value.replace(k, v) @@ -54,14 +54,11 @@ def date_format_to_human(value): def _add_incorrect_value_message(request, label): messages.warning( - request, _('Incorrect value in "%(field_name)s" filter') % { - 'field_name': label - } + request, _('Incorrect value in "%(field_name)s" filter') % {"field_name": label} ) def custom_title_filter(title, base_class=FieldListFilter): - class CustomTitledFilter(base_class): def __new__(cls, *args, **kwargs): filter_instance = base_class.create(*args, **kwargs) @@ -72,7 +69,6 @@ def __new__(cls, *args, **kwargs): class BaseCustomFilter(FieldListFilter): - """Base class for custom filters.""" def __init__(self, field, request, params, model, model_admin, field_path): @@ -83,18 +79,13 @@ def __init__(self, field, request, params, model, model_admin, field_path): self.choices_list = field.flatchoices except AttributeError: pass - super().__init__( - field, request, params, model, model_admin, field_path - ) + super().__init__(field, request, params, model, model_admin, field_path) - filter_title = getattr(field, '_filter_title', None) + filter_title = getattr(field, "_filter_title", None) if filter_title: self.title = filter_title - elif '__' in field_path: - self.title = '{} {}'.format( - field.model._meta.verbose_name, - self.title - ) + elif "__" in field_path: + self.title = "{} {}".format(field.model._meta.verbose_name, self.title) def value(self): """ @@ -115,10 +106,9 @@ def expected_parameters(self): class ChoicesListFilter(BaseCustomFilter): - """Renders filter form with choices field.""" - template = 'admin/filters/choices_filter.html' + template = "admin/filters/choices_filter.html" _choices_list = [] @property @@ -131,18 +121,18 @@ def choices_list(self, value): def choices(self, cl): yield { - 'selected': False, - 'value': '', - 'display': _('All'), - 'parameter_name': self.field_path + "selected": False, + "value": "", + "display": _("All"), + "parameter_name": self.field_path, } for lookup, title in self.choices_list: yield { - 'selected': smart_text(lookup) == self.value(), - 'value': lookup, - 'display': title, - 'parameter_name': self.field_path, + "selected": smart_text(lookup) == self.value(), + "value": lookup, + "display": title, + "parameter_name": self.field_path, } def queryset(self, request, queryset): @@ -151,63 +141,60 @@ def queryset(self, request, queryset): class BooleanListFilter(ChoicesListFilter): - _choices_list = [ - ('1', _('Yes')), - ('0', _('No')), + ("1", _("Yes")), + ("0", _("No")), ] class DateListFilter(BaseCustomFilter): - """Renders filter form with date field.""" - template = 'admin/filters/date_filter.html' + template = "admin/filters/date_filter.html" def __init__(self, field, request, params, model, model_admin, field_path): used_parameters = {} - self.parameter_name_start = field_path + '__start' - self.parameter_name_end = field_path + '__end' + self.parameter_name_start = field_path + "__start" + self.parameter_name_end = field_path + "__end" for param in self.expected_parameters(): try: - used_parameters[param] = params.pop(param, '') + used_parameters[param] = params.pop(param, "") except KeyError: pass - super().__init__( - field, request, params, model, model_admin, field_path - ) + super().__init__(field, request, params, model, model_admin, field_path) self.used_parameters = used_parameters def expected_parameters(self): return [self.parameter_name_start, self.parameter_name_end] def value(self): - return [ - self.used_parameters.get(param) - for param in self.expected_parameters() - ] + return [self.used_parameters.get(param) for param in self.expected_parameters()] def queryset(self, request, queryset): if any(self.value()): date = self.value() try: date_start = datetime.strptime( - date[0], get_format('DATE_INPUT_FORMATS')[0] + date[0], get_format("DATE_INPUT_FORMATS")[0] + ) + queryset = queryset.filter( + **{ + "{}__gte".format(self.field_path): date_start, + } ) - queryset = queryset.filter(**{ - '{}__gte'.format(self.field_path): date_start, - }) except ValueError: pass try: date_end = datetime.strptime( - date[1], get_format('DATE_INPUT_FORMATS')[0] + date[1], get_format("DATE_INPUT_FORMATS")[0] + ) + queryset = queryset.filter( + **{ + "{}__lte".format(self.field_path): date_end, + } ) - queryset = queryset.filter(**{ - '{}__lte'.format(self.field_path): date_end, - }) except ValueError: pass @@ -216,51 +203,48 @@ def queryset(self, request, queryset): def choices(self, cl): value = self.value() yield { - 'parameter_name_start': self.parameter_name_start, - 'parameter_name_end': self.parameter_name_end, - 'date_start': value[0], - 'date_end': value[1], - 'date_format': date_format_to_human( - get_format('DATE_INPUT_FORMATS')[0] - ) + "parameter_name_start": self.parameter_name_start, + "parameter_name_end": self.parameter_name_end, + "date_start": value[0], + "date_end": value[1], + "date_format": date_format_to_human(get_format("DATE_INPUT_FORMATS")[0]), } class VulnerabilitesByPatchDeadline(DateListFilter): - def queryset(self, request, queryset): from ralph.security.models import SecurityScan + if any(self.value()): filters = {} date_start, date_end = self.value() if date_start: - filters['vulnerabilities__patch_deadline__gte'] = date_start + filters["vulnerabilities__patch_deadline__gte"] = date_start if date_end: - filters['vulnerabilities__patch_deadline__lte'] = date_end - base_objects_ids = SecurityScan.objects.filter( - **filters - ).values_list('base_object_id', flat=True) + filters["vulnerabilities__patch_deadline__lte"] = date_end + base_objects_ids = SecurityScan.objects.filter(**filters).values_list( + "base_object_id", flat=True + ) queryset = queryset.filter(id__in=base_objects_ids) return queryset class NumberListFilter(DateListFilter): - """Renders filter form with decimal field.""" - template = 'admin/filters/number_filter.html' + template = "admin/filters/number_filter.html" def queryset(self, request, queryset): if any(self.value()): value = self.value() if value[0]: - queryset = queryset.filter(**{ - '{}__gte'.format(self.field_path): value[0] - }) + queryset = queryset.filter( + **{"{}__gte".format(self.field_path): value[0]} + ) if value[1]: - queryset = queryset.filter(**{ - '{}__lte'.format(self.field_path): value[1] - }) + queryset = queryset.filter( + **{"{}__lte".format(self.field_path): value[1]} + ) return queryset def choices(self, cl): @@ -271,16 +255,15 @@ def choices(self, cl): step = 1 yield { - 'parameter_name_start': self.parameter_name_start, - 'parameter_name_end': self.parameter_name_end, - 'start_value': value[0], - 'end_value': value[1], - 'step': step + "parameter_name_start": self.parameter_name_start, + "parameter_name_end": self.parameter_name_end, + "start_value": value[0], + "end_value": value[1], + "step": step, } class TextListFilter(BaseCustomFilter): - """Renders filter form with char field.""" template = "admin/filters/text_filter.html" @@ -291,38 +274,35 @@ def queryset(self, request, queryset): if self.value(): query = Q() for value in SEARCH_OR_SEPARATORS_REGEX.split(self.value()): - query |= Q( - **{'{}__icontains'.format(self.field_path): value.strip()} - ) + query |= Q(**{"{}__icontains".format(self.field_path): value.strip()}) return queryset.filter(query) def choices(self, cl): - return ({ - 'selected': self.value(), - 'parameter_name': self.field_path, - 'separators': self.separators, - 'multiple': self.multiple - },) + return ( + { + "selected": self.value(), + "parameter_name": self.field_path, + "separators": self.separators, + "multiple": self.multiple, + }, + ) class TagsListFilter(SimpleListFilter): - - title = _('Tags') - parameter_name = 'tags' - separators = ' or '.join(list(SEARCH_AND_SEPARATORS_REGEX.pattern[1:-1])) - template = 'admin/filters/text_filter.html' + title = _("Tags") + parameter_name = "tags" + separators = " or ".join(list(SEARCH_AND_SEPARATORS_REGEX.pattern[1:-1])) + template = "admin/filters/text_filter.html" def lookups(self, request, model_admin): - return ( - (1, _('Tags')), - ) + return ((1, _("Tags")),) def choices(self, cl): yield { - 'current_value': self.value() or '', - 'parameter_name': self.parameter_name, - 'separators': self.separators, - 'multiple': True, + "current_value": self.value() or "", + "parameter_name": self.parameter_name, + "separators": self.separators, + "multiple": True, } def queryset(self, request, queryset): @@ -337,6 +317,7 @@ class RelatedFieldListFilter(ChoicesListFilter): Filter for related fields (ForeignKeys) which is displayed as regular HTML select list (all options are fetched at once). """ + def label_for_instance(self, obj): return smart_text(obj) @@ -348,7 +329,6 @@ def choices_list(self): class RelatedAutocompleteFieldListFilter(RelatedFieldListFilter): - """Filter for Foregin key field.""" template = "admin/filters/related_filter.html" @@ -360,18 +340,18 @@ def __init__(self, field, request, params, model, model_admin, field_path): def value(self): value = super().value() - return value or '' + return value or "" def queryset(self, request, queryset): value = self.value() if not value: ids = [] else: - ids = value.split(',') + ids = value.split(",") q_param = models.Q() for id_ in ids: if id_ == self.empty_value: - q_param |= Q(**{'{}__isnull'.format(self.field_path): True}) + q_param |= Q(**{"{}__isnull".format(self.field_path): True}) else: q_param |= Q(**{self.field_path: id_}) try: @@ -384,7 +364,8 @@ def queryset(self, request, queryset): def get_related_url(self): return reverse( - 'admin:%s_%s_changelist' % ( + "admin:%s_%s_changelist" + % ( self.field_model._meta.app_label, self.field_model._meta.model_name, ), @@ -394,49 +375,51 @@ def get_prefetch_data(self): value = self.value() results = {} if value: - values = value.split(',') + values = value.split(",") prepend_empty = self.empty_value in values - queryset = self.field_model._default_manager.filter( - pk__in=values - ) + queryset = self.field_model._default_manager.filter(pk__in=values) results = get_results(queryset, True, prepend_empty) return json.dumps(results) def choices(self, cl): model_options = ( - self.field_model._meta.app_label, self.field_model._meta.model_name + self.field_model._meta.app_label, + self.field_model._meta.model_name, ) - model = get_field_by_relation_path( - self.model, self.field_path - ).model + model = get_field_by_relation_path(self.model, self.field_path).model widget_options = { - 'id': 'id_{}'.format(self.field_path), - 'query-ajax-url': reverse( - 'autocomplete-list', kwargs={ - 'app': model._meta.app_label, - 'model': model.__name__, - 'field': self.field.name - } - ) + '?prepend-empty=true', - 'multi': True, - 'detailsurl': reverse( - 'admin:{}_{}_autocomplete_details'.format(*model_options) + "id": "id_{}".format(self.field_path), + "query-ajax-url": reverse( + "autocomplete-list", + kwargs={ + "app": model._meta.app_label, + "model": model.__name__, + "field": self.field.name, + }, + ) + + "?prepend-empty=true", + "multi": True, + "detailsurl": reverse( + "admin:{}_{}_autocomplete_details".format(*model_options) ), } - return ({ - 'value': self.value(), - 'attrs': flatatt(widget_options), - 'name': self.field_path, - 'related_url': self.get_related_url(), - 'search_fields_info': "Search by: {}".format(self.title), - 'prefetch_data': self.get_prefetch_data(), - },) + return ( + { + "value": self.value(), + "attrs": flatatt(widget_options), + "name": self.field_path, + "related_url": self.get_related_url(), + "search_fields_info": "Search by: {}".format(self.title), + "prefetch_data": self.get_prefetch_data(), + }, + ) class TreeRelatedFieldListFilter(RelatedFieldListFilter): """ Related filter for TreeForeignKeys. """ + def __init__(self, field, request, params, model, model_admin, field_path): self.level_indicator = DEFAULT_LEVEL_INDICATOR super().__init__(field, request, params, model, model_admin, field_path) @@ -451,9 +434,7 @@ def _get_level_indicator(self, obj): def label_for_instance(self, obj): level_indicator = self._get_level_indicator(obj) - return mark_safe( - level_indicator + ' ' + conditional_escape(smart_text(obj)) - ) + return mark_safe(level_indicator + " " + conditional_escape(smart_text(obj))) def queryset(self, request, queryset): """ @@ -466,21 +447,22 @@ def queryset(self, request, queryset): _add_incorrect_value_message(request, self.title) raise IncorrectLookupParameters() else: - queryset = queryset.filter(**{ - self.field_path + '__in': root.get_descendants( - include_self=True - ) - }) + queryset = queryset.filter( + **{ + self.field_path + "__in": root.get_descendants( + include_self=True + ) + } + ) return queryset -class TreeRelatedAutocompleteFilterWithDescendants( - RelatedAutocompleteFieldListFilter -): +class TreeRelatedAutocompleteFilterWithDescendants(RelatedAutocompleteFieldListFilter): """ Autocomplete filter for ForeignKeys to `mptt.models.MPTTModel` with filtering by object and all its descendants. """ + def _get_descendants(self, request, root_id): try: root = self.field.remote_field.model.objects.get(pk=root_id) @@ -494,44 +476,43 @@ def queryset(self, request, queryset): if not value: ids = [] else: - ids = value.split(',') + ids = value.split(",") q_param = Q() for id_ in ids: if id_ == self.empty_value: - q_param |= Q(**{'{}__isnull'.format(self.field_path): True}) + q_param |= Q(**{"{}__isnull".format(self.field_path): True}) else: - q_param |= Q(**{ - '{}__in'.format(self.field_path): self._get_descendants( - request, id_ - ) - }) + q_param |= Q( + **{ + "{}__in".format(self.field_path): self._get_descendants( + request, id_ + ) + } + ) try: queryset = queryset.filter(q_param) except ValueError: messages.warning( - request, _('Incorrect value in "%(field_name)s" filter') % { - 'field_name': self.title - } + request, + _('Incorrect value in "%(field_name)s" filter') + % {"field_name": self.title}, ) raise IncorrectLookupParameters() return queryset class IPFilter(SimpleListFilter): - - title = _('IP') - parameter_name = 'ip' + title = _("IP") + parameter_name = "ip" template = "admin/filters/text_filter.html" def lookups(self, request, model_admin): - return ( - (1, _('IP')), - ) + return ((1, _("IP")),) def choices(self, cl): yield { - 'selected': self.value() or '', - 'parameter_name': self.parameter_name, + "selected": self.value() or "", + "parameter_name": self.parameter_name, } def queryset(self, request, queryset): @@ -549,14 +530,12 @@ def queryset(self, request, queryset): class MacAddressFilter(SimpleListFilter): - title = _('MAC Address') - parameter_name = 'mac' - template = 'admin/filters/text_filter.html' + title = _("MAC Address") + parameter_name = "mac" + template = "admin/filters/text_filter.html" def lookups(self, request, model_admin): - return ( - (1, _('MAC Address')), - ) + return ((1, _("MAC Address")),) def queryset(self, request, queryset): value = self.value() @@ -574,15 +553,14 @@ def queryset(self, request, queryset): def choices(self, cl): yield { - 'selected': self.value(), - 'parameter_name': self.parameter_name, + "selected": self.value(), + "parameter_name": self.parameter_name, } class LiquidatedStatusFilter(SimpleListFilter): - - title = _('show liquidated') - parameter_name = 'liquidated' + title = _("show liquidated") + parameter_name = "liquidated" template = "admin/filters/checkbox_filter.html" def __init__(self, request, params, model, model_admin): @@ -590,20 +568,18 @@ def __init__(self, request, params, model, model_admin): self.model = model def lookups(self, request, model_admin): - return ( - (1, _('show liquidated')), - ) + return ((1, _("show liquidated")),) def choices(self, cl): yield { - 'selected': self.value() or False, - 'parameter_name': self.parameter_name, + "selected": self.value() or False, + "parameter_name": self.parameter_name, } def queryset(self, request, queryset): if not self.value(): liquidated_status = self.model._meta.get_field( - 'status' + "status" ).choices.liquidated.id queryset = queryset.exclude(status=liquidated_status) @@ -611,28 +587,26 @@ def queryset(self, request, queryset): class BaseObjectHostnameFilter(SimpleListFilter): - title = _('Hostname') - parameter_name = 'hostname' - template = 'admin/filters/text_filter.html' + title = _("Hostname") + parameter_name = "hostname" + template = "admin/filters/text_filter.html" def queryset(self, request, queryset): if not self.value(): return queryset queries = [ - Q(hostname__icontains=self.value()) | - Q(ethernet_set__ipaddress__hostname__icontains=self.value()) + Q(hostname__icontains=self.value()) + | Q(ethernet_set__ipaddress__hostname__icontains=self.value()) ] return queryset.filter(*queries).distinct() def lookups(self, request, model_admin): - return ( - (1, _('Hostname')), - ) + return ((1, _("Hostname")),) def choices(self, cl): yield { - 'selected': self.value(), - 'parameter_name': self.parameter_name, + "selected": self.value(), + "parameter_name": self.parameter_name, } @@ -644,37 +618,35 @@ def register_custom_filters(): """ field_filter_mapper = [ (lambda f: bool(f.choices), ChoicesListFilter), - (lambda f: isinstance(f, ( - models.DecimalField, models.IntegerField - )), NumberListFilter), - (lambda f: isinstance(f, ( - models.BooleanField, models.NullBooleanField - )), BooleanListFilter), + ( + lambda f: isinstance(f, (models.DecimalField, models.IntegerField)), + NumberListFilter, + ), + ( + lambda f: isinstance(f, (models.BooleanField, models.NullBooleanField)), + BooleanListFilter, + ), (lambda f: isinstance(f, (models.DateField)), DateListFilter), - (lambda f: isinstance(f, ( - models.CharField, models.TextField, models.IntegerField - )), TextListFilter), ( - lambda f: isinstance(f, TreeForeignKey), - TreeRelatedFieldListFilter + lambda f: isinstance( + f, (models.CharField, models.TextField, models.IntegerField) + ), + TextListFilter, ), + (lambda f: isinstance(f, TreeForeignKey), TreeRelatedFieldListFilter), ( lambda f: ( - isinstance(f, models.ForeignKey) and - not getattr(f, '_autocomplete', True) + isinstance(f, models.ForeignKey) + and not getattr(f, "_autocomplete", True) ), - RelatedFieldListFilter + RelatedFieldListFilter, ), ( - lambda f: isinstance(f, ( - models.ForeignKey, models.ManyToManyField - )), - RelatedAutocompleteFieldListFilter + lambda f: isinstance(f, (models.ForeignKey, models.ManyToManyField)), + RelatedAutocompleteFieldListFilter, ), (lambda f: isinstance(f, TaggableManager), TagsListFilter), ] for func, filter_class in field_filter_mapper: - FieldListFilter.register( - func, filter_class, take_priority=True - ) + FieldListFilter.register(func, filter_class, take_priority=True) diff --git a/src/ralph/admin/helpers.py b/src/ralph/admin/helpers.py index 62c8bebae5..ad9fd35018 100644 --- a/src/ralph/admin/helpers.py +++ b/src/ralph/admin/helpers.py @@ -10,10 +10,8 @@ def get_admin_url(obj, action): return reverse( - "admin:{}_{}_{}".format( - obj._meta.app_label, obj._meta.model_name, action - ), - args=(obj.id,) + "admin:{}_{}_{}".format(obj._meta.app_label, obj._meta.model_name, action), + args=(obj.id,), ) @@ -62,7 +60,7 @@ def getattr_dunder(obj, attr, default=None): if attr contains double underscores. """ - first, dunder, rest = attr.partition('__') + first, dunder, rest = attr.partition("__") value = getattr(obj, first, default) if rest: return getattr_dunder(value, rest, default) @@ -108,8 +106,8 @@ def generate_html_link(base_url, label, params=None): return '{label}'.format( base_url=base_url, - params=('?' + urlencode(params or {})) if params else '', - label=str(label).replace(' ', ' ') + params=("?" + urlencode(params or {})) if params else "", + label=str(label).replace(" ", " "), ) @@ -123,11 +121,11 @@ def get_client_ip(request): Returns: IP as a string """ - x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") if x_forwarded_for: - ip = x_forwarded_for.split(',')[0] + ip = x_forwarded_for.split(",")[0] else: - ip = request.META.get('REMOTE_ADDR') + ip = request.META.get("REMOTE_ADDR") return ip @@ -135,13 +133,14 @@ class CastToInteger(Func): """ A helper class for casting values to signed integer in database. """ - function = 'CAST' - template = '%(function)s(%(expressions)s as %(integer_type)s)' + + function = "CAST" + template = "%(function)s(%(expressions)s as %(integer_type)s)" def __init__(self, *expressions, **extra): super().__init__(*expressions, **extra) - self.extra['integer_type'] = 'INTEGER' + self.extra["integer_type"] = "INTEGER" def as_mysql(self, compiler, connection): - self.extra['integer_type'] = 'SIGNED' + self.extra["integer_type"] = "SIGNED" return super().as_sql(compiler, connection) diff --git a/src/ralph/admin/m2m.py b/src/ralph/admin/m2m.py index 23b23549b6..e3e52d3015 100644 --- a/src/ralph/admin/m2m.py +++ b/src/ralph/admin/m2m.py @@ -39,6 +39,7 @@ class AuthorAdmin(admin.ModelAdmin): inlines = [AuthorArticlesM2MInline] ``` """ + from functools import partial from django import forms @@ -50,7 +51,7 @@ class AuthorAdmin(admin.ModelAdmin): from django.forms.models import ( BaseInlineFormSet, modelform_defines_fields, - modelformset_factory + modelformset_factory, ) from django.utils.text import get_text_list from django.utils.translation import gettext_lazy as _ diff --git a/src/ralph/admin/mixins.py b/src/ralph/admin/mixins.py index f359061786..1d610ab7ce 100644 --- a/src/ralph/admin/mixins.py +++ b/src/ralph/admin/mixins.py @@ -34,7 +34,7 @@ from ralph.lib.mixins.models import AdminAbsoluteUrlMixin from ralph.lib.permissions.admin import ( PermissionAdminMixin, - PermissionsPerObjectFormMixin + PermissionsPerObjectFormMixin, ) from ralph.lib.permissions.models import PermByFieldMixin from ralph.lib.permissions.views import PermissionViewMetaClass @@ -42,19 +42,22 @@ logger = logging.getLogger(__name__) FORMFIELD_FOR_DBFIELD_DEFAULTS = { - models.DateField: {'widget': widgets.AdminDateWidget}, - models.DateTimeField: {'widget': widgets.ReadOnlyWidget}, - TicketIdField: {'widget': TicketIdFieldWidget}, + models.DateField: {"widget": widgets.AdminDateWidget}, + models.DateTimeField: {"widget": widgets.ReadOnlyWidget}, + TicketIdField: {"widget": TicketIdFieldWidget}, } def get_inline_media(): - js = map(lambda x: os.path.join(*x), [ - ('admin', 'js', 'inlines.js'), - ('src', 'js', 'ralph-autocomplete.js'), - ]) + js = map( + lambda x: os.path.join(*x), + [ + ("admin", "js", "inlines.js"), + ("src", "js", "ralph-autocomplete.js"), + ], + ) return forms.Media( - js=[static('%s' % url) for url in js], + js=[static("%s" % url) for url in js], ) @@ -73,13 +76,13 @@ def initialize_search_form(model, context): try: field = get_field_by_relation_path(model, field_name) except FieldDoesNotExist: - verbose_search_fields.append(field_name.split('__')[-1]) + verbose_search_fields.append(field_name.split("__")[-1]) else: verbose_search_fields.append(field.verbose_name) - context['search_fields'] = sorted(set(verbose_search_fields)) - context['model_verbose_name'] = model._meta.verbose_name - context['search_url'] = reverse( - 'admin:{app_label}_{model_name}_changelist'.format( + context["search_fields"] = sorted(set(verbose_search_fields)) + context["model_verbose_name"] = model._meta.verbose_name + context["search_url"] = reverse( + "admin:{app_label}_{model_name}_changelist".format( app_label=model._meta.app_label, model_name=model._meta.model_name, ) @@ -97,11 +100,14 @@ def formfield_for_foreignkey(self, db_field, request=None, **kwargs): if db_field.name in self.raw_id_fields: kw = {} if db_field.name in self.raw_id_override_parent: - kw['rel_to'] = self.raw_id_override_parent[db_field.name] - - kwargs['widget'] = widgets.AutocompleteWidget( - field=db_field, admin_site=self.admin_site, - using=kwargs.get('using'), request=request, **kw + kw["rel_to"] = self.raw_id_override_parent[db_field.name] + + kwargs["widget"] = widgets.AutocompleteWidget( + field=db_field, + admin_site=self.admin_site, + using=kwargs.get("using"), + request=request, + **kw, ) return db_field.formfield(**kwargs) else: @@ -109,13 +115,16 @@ def formfield_for_foreignkey(self, db_field, request=None, **kwargs): def formfield_for_manytomany(self, db_field, request=None, **kwargs): if db_field.name in self.raw_id_fields: - kw = {'multi': True} + kw = {"multi": True} if db_field.name in self.raw_id_override_parent: - kw['rel_to'] = self.raw_id_override_parent[db_field.name] - - kwargs['widget'] = widgets.AutocompleteWidget( - field=db_field, admin_site=self.admin_site, - using=kwargs.get('using'), request=request, **kw + kw["rel_to"] = self.raw_id_override_parent[db_field.name] + + kwargs["widget"] = widgets.AutocompleteWidget( + field=db_field, + admin_site=self.admin_site, + using=kwargs.get("using"), + request=request, + **kw, ) return db_field.formfield(**kwargs) else: @@ -139,14 +148,14 @@ class RedirectSearchToObjectMixin(object): def changelist_view(self, request, *args, **kwargs): response = super().changelist_view(request, *args, **kwargs) - context_data = getattr(response, 'context_data', None) - cl = context_data.get('cl') if context_data else None + context_data = getattr(response, "context_data", None) + cl = context_data.get("cl") if context_data else None if ( - not context_data or - not cl or - not hasattr(cl, 'result_count') or - not settings.REDIRECT_TO_DETAIL_VIEW_IF_ONE_SEARCH_RESULT or - not self.redirect_to_detail_view_if_one_search_result + not context_data + or not cl + or not hasattr(cl, "result_count") + or not settings.REDIRECT_TO_DETAIL_VIEW_IF_ONE_SEARCH_RESULT + or not self.redirect_to_detail_view_if_one_search_result ): return response filtered_results = list(request.GET.keys()) @@ -154,18 +163,16 @@ def changelist_view(self, request, *args, **kwargs): if filtered_results and not ordering and cl.result_count == 1: obj = cl.result_list[0] if issubclass(obj.__class__, AdminAbsoluteUrlMixin): - messages.info(request, _('Found exactly one result.')) - return HttpResponseRedirect( - cl.result_list[0].get_absolute_url() - ) + messages.info(request, _("Found exactly one result.")) + return HttpResponseRedirect(cl.result_list[0].get_absolute_url()) return response class RalphAdminChecks(admin.checks.ModelAdminChecks): exclude_models = ( - ('auth', 'Group'.lower()), - ('assets', 'BaseObject'.lower()), - ('contenttypes', 'ContentType'.lower()) + ("auth", "Group".lower()), + ("assets", "BaseObject".lower()), + ("contenttypes", "ContentType".lower()), ) def check(self, model, **kwargs): @@ -178,15 +185,9 @@ def _check_form(self, model): Check if form subclasses RalphAdminFormMixin """ result = super()._check_form(model) - if ( - hasattr(model, 'form') and - not issubclass(model.form, RalphAdminFormMixin) - ): + if hasattr(model, "form") and not issubclass(model.form, RalphAdminFormMixin): result += admin.checks.must_inherit_from( - parent='RalphAdminFormMixin', - option='form', - obj=model, - id='admin.E016' + parent="RalphAdminFormMixin", option="form", obj=model, id="admin.E016" ) return result @@ -198,14 +199,14 @@ def _check_absolute_url(self, model): if (opts.app_label, opts.model_name) in self.exclude_models: return [] msg = "The model '{}' must inherit from 'AdminAbsoluteUrlMixin'." - hint = 'Add AdminAbsoluteUrlMixin from ralph.lib.mixns.models to model.' # noqa + hint = "Add AdminAbsoluteUrlMixin from ralph.lib.mixns.models to model." # noqa if not issubclass(model, AdminAbsoluteUrlMixin): return [ checks.Error( msg.format(model), hint=hint, obj=model, - id='admin.E101', + id="admin.E101", ), ] return [] @@ -218,18 +219,17 @@ def lookup_allowed(self, *args, **kwargs): return True def _is_graph_preview_view(self, request): - return request.GET.get('graph-query', '') + return request.GET.get("graph-query", "") def changelist_view(self, request, extra_context=None): - extra_context['is_graph_preview_view'] = self._is_graph_preview_view( - request - ) + extra_context["is_graph_preview_view"] = self._is_graph_preview_view(request) return super().changelist_view(request, extra_context) def get_list_filter(self, request): from ralph.dashboards.admin_filters import ByGraphFilter + filters = super().get_list_filter(request) or [] - is_graph_model = getattr(self.model, '_allow_in_dashboard', False) + is_graph_model = getattr(self.model, "_allow_in_dashboard", False) if is_graph_model and ByGraphFilter not in filters: filters.append(ByGraphFilter) @@ -241,8 +241,8 @@ class RalphAdminMixin(DashboardChangelistMixin, RalphAutocompleteMixin): list_views = None change_views = None - change_list_template = 'admin/change_list.html' - change_form_template = 'admin/change_form.html' + change_list_template = "admin/change_list.html" + change_form_template = "admin/change_form.html" checks_class = RalphAdminChecks form = RalphAdminForm # List of fields that are to be excluded from fillable on bulk edit @@ -251,8 +251,8 @@ class RalphAdminMixin(DashboardChangelistMixin, RalphAutocompleteMixin): def __init__(self, *args, **kwargs): self.list_views = copy(self.list_views) or [] - if kwargs.get('change_views'): - self.change_views = copy(kwargs.pop('change_views', [])) + if kwargs.get("change_views"): + self.change_views = copy(kwargs.pop("change_views", [])) else: self.change_views = copy(self.change_views) or [] super().__init__(*args, **kwargs) @@ -266,8 +266,8 @@ def get_form(self, request, obj=None, **kwargs): def has_view_permission(self, request, obj=None): opts = self.opts - codename = get_permission_codename('view', opts) - return request.user.has_perm('%s.%s' % (opts.app_label, codename)) + codename = get_permission_codename("view", opts) + return request.user.has_perm("%s.%s" % (opts.app_label, codename)) def has_change_permission(self, request, obj=None): if obj: @@ -277,6 +277,7 @@ def has_change_permission(self, request, obj=None): def get_changelist(self, request, **kwargs): from ralph.admin.views.main import RalphChangeList + return RalphChangeList def get_list_display_links(self, request, list_display): @@ -292,30 +293,28 @@ def changelist_view(self, request, extra_context=None): """Override change list from django.""" if extra_context is None: extra_context = {} - extra_context['app_label'] = self.model._meta.app_label - extra_context['header_obj_name'] = self.model._meta.verbose_name_plural + extra_context["app_label"] = self.model._meta.app_label + extra_context["header_obj_name"] = self.model._meta.verbose_name_plural views = [] for view in self.list_views: views.append(view) - extra_context['list_views'] = views + extra_context["list_views"] = views if self.get_actions(request) or self.list_filter: - extra_context['has_filters'] = True + extra_context["has_filters"] = True - extra_context['bulk_edit'] = request.GET.get(BULK_EDIT_VAR, False) - if extra_context['bulk_edit']: - bulk_back_url = request.session.get('bulk_back_url') + extra_context["bulk_edit"] = request.GET.get(BULK_EDIT_VAR, False) + if extra_context["bulk_edit"]: + bulk_back_url = request.session.get("bulk_back_url") if not bulk_back_url: - bulk_back_url = request.META.get('HTTP_REFERER') - request.session['bulk_back_url'] = bulk_back_url - extra_context['bulk_back_url'] = bulk_back_url - extra_context['has_filters'] = False + bulk_back_url = request.META.get("HTTP_REFERER") + request.session["bulk_back_url"] = bulk_back_url + extra_context["bulk_back_url"] = bulk_back_url + extra_context["has_filters"] = False else: - request.session['bulk_back_url'] = None + request.session["bulk_back_url"] = None self._initialize_search_form(extra_context) - return super(RalphAdminMixin, self).changelist_view( - request, extra_context - ) + return super(RalphAdminMixin, self).changelist_view(request, extra_context) def get_actions(self, request): """Override get actions method.""" @@ -323,33 +322,28 @@ def get_actions(self, request): # Hide checkbox on bulk edit page return [] actions = super().get_actions(request) - if ( - not self.has_delete_permission(request) and - 'delete_selected' in actions - ): - del actions['delete_selected'] + if not self.has_delete_permission(request) and "delete_selected" in actions: + del actions["delete_selected"] return actions - def changeform_view( - self, request, object_id=None, form_url='', extra_context=None - ): + def changeform_view(self, request, object_id=None, form_url="", extra_context=None): if extra_context is None: extra_context = {} views = [] if object_id: for view in self.change_views: views.append(view) - extra_context['change_views'] = views - extra_context['header_obj_name'] = self.model._meta.verbose_name + extra_context["change_views"] = views + extra_context["header_obj_name"] = self.model._meta.verbose_name self._initialize_search_form(extra_context) - extra_context['admin_view'] = self + extra_context["admin_view"] = self return super(RalphAdminMixin, self).changeform_view( request, object_id, form_url, extra_context ) def formfield_for_manytomany(self, db_field, request=None, **kwargs): - if db_field.name in ('user_permissions', 'permissions'): - kwargs['widget'] = widgets.PermissionsSelectWidget() + if db_field.name in ("user_permissions", "permissions"): + kwargs["widget"] = widgets.PermissionsSelectWidget() return db_field.formfield(**kwargs) return super().formfield_for_manytomany(db_field, request, **kwargs) @@ -365,24 +359,20 @@ def get_changelist_form(self, request, **kwargs): widget = field.formfield().widget # Added vTextField CSS class to widget, # because Django admin form has it default - widget.attrs['class'] = 'vTextField no-fillable' + widget.attrs["class"] = "vTextField no-fillable" widgets[field_name] = widget if widgets: - kwargs['widgets'] = widgets + kwargs["widgets"] = widgets return super().get_changelist_form(request, **kwargs) def _add_recovery_to_extra_context(self, extra_context): extra_context = extra_context or {} - extra_context['in_recovery_mode'] = True + extra_context["in_recovery_mode"] = True return extra_context - def revision_view( - self, request, object_id, version_id, extra_context=None - ): + def revision_view(self, request, object_id, version_id, extra_context=None): extra_context = self._add_recovery_to_extra_context(extra_context) - return super().revision_view( - request, object_id, version_id, extra_context - ) + return super().revision_view(request, object_id, version_id, extra_context) def recover_view(self, request, version_id, extra_context=None): extra_context = self._add_recovery_to_extra_context(extra_context) @@ -405,20 +395,18 @@ def get_export_queryset(self, request): fk_fields = [] for name, field in resource.fields.items(): if ( - isinstance(field.widget, ForeignKeyWidget) and - not getattr(field, '_exclude_in_select_related', False) and - not isinstance(getattr(queryset.model, name, None), property) + isinstance(field.widget, ForeignKeyWidget) + and not getattr(field, "_exclude_in_select_related", False) + and not isinstance(getattr(queryset.model, name, None), property) ): fk_fields.append(field.attribute) if fk_fields: queryset = queryset.select_related(*fk_fields) - resource_select_related = getattr(resource._meta, 'select_related', []) + resource_select_related = getattr(resource._meta, "select_related", []) if resource_select_related: queryset = queryset.select_related(*resource_select_related) - resource_prefetch_related = getattr( - resource._meta, 'prefetch_related', [] - ) + resource_prefetch_related = getattr(resource._meta, "prefetch_related", []) if resource_prefetch_related: queryset = queryset.prefetch_related(*resource_prefetch_related) return list(queryset) @@ -428,7 +416,7 @@ def get_export_resource_class(self): If `export_class` is defined in Admin, use it. """ resource_class = self.get_resource_class() - export_class = getattr(resource_class, 'export_class', None) + export_class = getattr(resource_class, "export_class", None) if export_class: return export_class return resource_class @@ -436,35 +424,34 @@ def get_export_resource_class(self): def get_queryset(self, request): # if it is "exporter" request, try to use `_export_queryset_manager` # manager defined in admin - if hasattr(request, '_is_export') and self._export_queryset_manager: - logger.info('Using {} manager for export'.format( - self._export_queryset_manager - )) + if hasattr(request, "_is_export") and self._export_queryset_manager: + logger.info( + "Using {} manager for export".format(self._export_queryset_manager) + ) return getattr(self.model, self._export_queryset_manager).all() return super().get_queryset(request) class ProxyModelsPermissionsMixin(object): - def has_add_permission(self, request): if not self.model._meta.proxy: return super().has_add_permission(request) opts = self.model._meta - codename = get_permission_codename('add', opts) + codename = get_permission_codename("add", opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename)) def has_change_permission(self, request, obj=None): if not self.model._meta.proxy: return super().has_change_permission(request, obj) opts = self.model._meta - codename = get_permission_codename('change', opts) + codename = get_permission_codename("change", opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename)) def has_delete_permission(self, request, obj=None): if not self.model._meta.proxy: return super().has_delete_permission(request, obj) opts = self.model._meta - codename = get_permission_codename('delete', opts) + codename = get_permission_codename("delete", opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename)) @@ -488,29 +475,19 @@ class RalphMPTTAdmin(MPTTModelAdmin, RalphAdmin): class RalphInlineMixin(object): # display change link for inline row in popup - change_link_url_params = '_popup=1' + change_link_url_params = "_popup=1" -class RalphTabularInline( - RalphInlineMixin, - RalphAutocompleteMixin, - admin.TabularInline -): +class RalphTabularInline(RalphInlineMixin, RalphAutocompleteMixin, admin.TabularInline): pass -class RalphStackedInline( - RalphInlineMixin, - RalphAutocompleteMixin, - admin.StackedInline -): +class RalphStackedInline(RalphInlineMixin, RalphAutocompleteMixin, admin.StackedInline): pass class RalphGenericTabularInline( - RalphInlineMixin, - RalphAutocompleteMixin, - GenericTabularInline + RalphInlineMixin, RalphAutocompleteMixin, GenericTabularInline ): pass @@ -518,21 +495,18 @@ class RalphGenericTabularInline( class RalphBaseTemplateView(TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['site_header'] = settings.ADMIN_SITE_HEADER - context['site_title'] = settings.ADMIN_SITE_TITLE + context["site_header"] = settings.ADMIN_SITE_HEADER + context["site_title"] = settings.ADMIN_SITE_TITLE # checks if user is allowed to see elements in template - context['has_permission'] = self.request.user.is_authenticated + context["has_permission"] = self.request.user.is_authenticated return context -class RalphTemplateView( - RalphBaseTemplateView, metaclass=PermissionViewMetaClass -): +class RalphTemplateView(RalphBaseTemplateView, metaclass=PermissionViewMetaClass): pass class BulkEditChangeListMixin(object): - def get_queryset(self, request): """Override django admin get queryset method.""" qs = super().get_queryset(request) @@ -554,21 +528,23 @@ def get_list_display(self, request): bulk_list_edit = self.bulk_edit_list if issubclass(self.model, PermByFieldMixin): bulk_list_display = [ - field for field in self.bulk_edit_list + field + for field in self.bulk_edit_list if self.model.has_access_to_field( - field, request.user, action='view' + field, request.user, action="view" ) ] bulk_list_edit = [ - field for field in bulk_list_display + field + for field in bulk_list_display if self.model.has_access_to_field( - field, request.user, action='change' + field, request.user, action="change" ) ] # overwrite displayed fields in bulk-edit mode list_display = bulk_list_display.copy() - if 'id' not in list_display: - list_display.insert(0, 'id') + if "id" not in list_display: + list_display.insert(0, "id") # list editable is subset of list display in this case self.list_editable = bulk_list_edit return list_display @@ -579,14 +555,14 @@ def bulk_edit_action(self, request, queryset): Custom bulk edit action. """ selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) - url = reverse('admin:{}'.format(request.resolver_match.url_name)) + url = reverse("admin:{}".format(request.resolver_match.url_name)) id_list = [(BULK_EDIT_VAR_IDS, i) for i in selected] return HttpResponseRedirect( - '{}?{}=1&{}'.format( + "{}?{}=1&{}".format( url, BULK_EDIT_VAR, urllib.parse.urlencode(id_list), ) ) - bulk_edit_action.short_description = 'Bulk edit' + bulk_edit_action.short_description = "Bulk edit" diff --git a/src/ralph/admin/signals.py b/src/ralph/admin/signals.py index a8c40edde3..f5215ac459 100644 --- a/src/ralph/admin/signals.py +++ b/src/ralph/admin/signals.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- import django.dispatch -post_transition = django.dispatch.Signal(['user', 'assets', 'transition']) +post_transition = django.dispatch.Signal(["user", "assets", "transition"]) diff --git a/src/ralph/admin/sites.py b/src/ralph/admin/sites.py index 950edfdf20..1513909600 100644 --- a/src/ralph/admin/sites.py +++ b/src/ralph/admin/sites.py @@ -7,13 +7,13 @@ class RalphAdminSiteMixin(object): - """Ralph admin site mixin.""" + site_header = settings.ADMIN_SITE_HEADER site_title = settings.ADMIN_SITE_TITLE - index_template = 'admin/index.html' - app_index_template = 'admin/app_index.html' - object_history_template = 'admin/object_history.html' + index_template = "admin/index.html" + app_index_template = "admin/app_index.html" + object_history_template = "admin/object_history.html" def _get_views(self, admin): return (admin.change_views or []) + (admin.list_views or []) @@ -30,22 +30,23 @@ def register(self, model_or_iterable, *args, **kwargs): def get_urls(self, *args, **kwargs): """Override django admin site get_urls method.""" - urlpatterns = super(RalphAdminSiteMixin, self).get_urls( - *args, **kwargs - ) + urlpatterns = super(RalphAdminSiteMixin, self).get_urls(*args, **kwargs) for model, model_admin in self._registry.items(): for view in self._get_views(model_admin): - urlpatterns.insert(0, url( - view.get_url_pattern(model), - view.as_view(), - { - 'model': model, - 'views': getattr( - model_admin, '{}_views'.format(view._type), [] - ), - }, - name=view.url_to_reverse - )) + urlpatterns.insert( + 0, + url( + view.get_url_pattern(model), + view.as_view(), + { + "model": model, + "views": getattr( + model_admin, "{}_views".format(view._type), [] + ), + }, + name=view.url_to_reverse, + ), + ) return urlpatterns def get_extra_view_menu_items(self): @@ -55,12 +56,11 @@ def get_extra_view_menu_items(self): def get_item(model, view, change_view=False): url = view.url_with_namespace if change_view: - url += ' object.id' - return {'title': view.label, 'url': url} + url += " object.id" + return {"title": view.label, "url": url} + for model, model_admin in self._registry.items(): - name = '{}_{}'.format( - model._meta.app_label, model._meta.model_name - ) + name = "{}_{}".format(model._meta.app_label, model._meta.model_name) for view in model_admin.list_views or []: items[name].append(get_item(model, view)) for view in model_admin.change_views or []: @@ -69,9 +69,10 @@ def get_item(model, view, change_view=False): def index(self, request, extra_context=None): from ralph.data_center.models import DataCenter + if extra_context is None: extra_context = {} - extra_context['data_centers'] = DataCenter.objects.filter( + extra_context["data_centers"] = DataCenter.objects.filter( show_on_dashboard=True ) return super().index(request, extra_context) @@ -83,8 +84,7 @@ def get_admin_instance_for_model(self, model_class): class RalphAdminSite(RalphAdminSiteMixin, AdminSite): def each_context(self, request): context = super(RalphAdminSite, self).each_context(request) - context['google_tag_manager_tag_id'] = \ - settings.GOOGLE_TAG_MANAGER_TAG_ID + context["google_tag_manager_tag_id"] = settings.GOOGLE_TAG_MANAGER_TAG_ID return context diff --git a/src/ralph/admin/sitetrees.py b/src/ralph/admin/sitetrees.py index ca02e7c660..f5b0a0f15c 100644 --- a/src/ralph/admin/sitetrees.py +++ b/src/ralph/admin/sitetrees.py @@ -16,26 +16,28 @@ def ralph_item(*args, **kwargs): - kwargs.setdefault('access_loggedin', True) + kwargs.setdefault("access_loggedin", True) # create access_by_perms entries by iterating through all children # and extracting app and model name from it # permission is created in '.{add|change|view}_' format - access_by_perms = kwargs.get('access_by_perms', []) + access_by_perms = kwargs.get("access_by_perms", []) if isinstance(access_by_perms, (str, int)): access_by_perms = [access_by_perms] - for child in kwargs.get('children', []): - if hasattr(child, '_model') and hasattr(child, '_app'): + for child in kwargs.get("children", []): + if hasattr(child, "_model") and hasattr(child, "_app"): model = child._model.lower() app = child._app.lower() - access_by_perms.extend([ - '{}.add_{}'.format(app, model), - '{}.change_{}'.format(app, model), - '{}.view_{}'.format(app, model), - ]) - elif hasattr(child, 'permissions'): + access_by_perms.extend( + [ + "{}.add_{}".format(app, model), + "{}.change_{}".format(app, model), + "{}.view_{}".format(app, model), + ] + ) + elif hasattr(child, "permissions"): access_by_perms.extend(child.permissions) if access_by_perms: - kwargs['access_by_perms'] = list(set(access_by_perms)) + kwargs["access_by_perms"] = list(set(access_by_perms)) return item(*args, **kwargs) @@ -44,10 +46,7 @@ def ralph_item(*args, **kwargs): def get_menu_items_for_admin(name, perm): # TODO: detailed permissions for extra views - return [ - ralph_item(access_by_perms=perm, **view) - for view in extra_views[name] - ] + return [ralph_item(access_by_perms=perm, **view) for view in extra_views[name]] def section(section_name, app, model): @@ -55,30 +54,28 @@ def section(section_name, app, model): model_class = apps.get_model(app, model) # support for proxy model beacause this bug # https://code.djangoproject.com/ticket/11154 - change_perm = '{}.change_{}'.format(app, model) + change_perm = "{}.change_{}".format(app, model) item = ralph_item( title=section_name, - url='admin:{}_{}_changelist'.format(app, model), - access_by_perms='{}.view_{}'.format(app, model), + url="admin:{}_{}_changelist".format(app, model), + access_by_perms="{}.view_{}".format(app, model), perms_mode_all=False, children=[ ralph_item( - title=_('Add {}'.format( - model_class._meta.verbose_name.lower() - )), - url='admin:{}_{}_add'.format(app, model), - access_by_perms='{}.add_{}'.format(app, model), + title=_("Add {}".format(model_class._meta.verbose_name.lower())), + url="admin:{}_{}_add".format(app, model), + access_by_perms="{}.add_{}".format(app, model), ), ralph_item( - title='{{ original }}', - url='admin:{}_{}_change original.id'.format(app, model), + title="{{ original }}", + url="admin:{}_{}_change original.id".format(app, model), access_by_perms=change_perm, children=get_menu_items_for_admin( - '{}_{}'.format(app, model), + "{}_{}".format(app, model), change_perm, ), ), - ] + ], ) # save app and model info to create permissions entries later item._app = app @@ -87,253 +84,243 @@ def section(section_name, app, model): sitetrees = [ - tree('ralph_admin', items=[ - ralph_item( - title=_('Data Center'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('All hosts'), 'data_center', 'DCHost'), - ralph_item( - title=_('DC Visualization'), - url='dc_view', - access_by_perms='accounts.can_view_extra_serverroomview' - ), - section(_('Hardware'), 'data_center', 'DataCenterAsset'), - section(_('Virtual Servers'), 'virtual', 'VirtualServer'), - section(_('Clusters'), 'data_center', 'cluster'), - section(_('Data Centers'), 'data_center', 'DataCenter'), - section(_('Racks'), 'data_center', 'Rack'), - section(_('Rack accessories'), 'data_center', 'RackAccessory'), - section(_('accessories'), 'data_center', 'Accessory'), - section(_('Databases'), 'data_center', 'Database'), - section(_('Disk Shares'), 'data_center', 'DiskShare'), - section(_('Server Rooms'), 'data_center', 'ServerRoom'), - section(_('VIPs'), 'data_center', 'VIP'), - section(_('Preboots'), 'deployment', 'Preboot'), - section( - _('Preboot configuration'), 'deployment', - 'PrebootConfiguration' - ), - section(_('Preboot files'), 'deployment', 'PrebootFile'), - ], - ), - ralph_item( - title=_('Cloud'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Cloud hosts'), 'virtual', 'CloudHost'), - section(_('Cloud projects'), 'virtual', 'CloudProject'), - section(_('Cloud flavors'), 'virtual', 'CloudFlavor'), - section(_('Cloud providers'), 'virtual', 'CloudProvider'), - section(_('Cloud images'), 'virtual', 'CloudImage'), - ], - ), - ralph_item( - title=_('Back Office'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Access Cards'), 'access_cards', 'AccessCard'), - section(_('Hardware'), 'back_office', 'backofficeasset'), - section(_('SIM Cards'), 'sim_cards', 'SIMCard'), - section(_('Accessory'), 'accessories', 'Accessory'), - ] - ), - ralph_item( - title=_('Networks'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Networks'), 'networks', 'network'), - section( - _('Network environments'), 'networks', 'networkenvironment' - ), - section(_('Network kind'), 'networks', 'networkkind'), - section(_('IP Addresses'), 'networks', 'ipaddress'), - section(_('DHCP Servers'), 'dhcp', 'DHCPServer'), - section(_('DNS Server Groups'), 'dhcp', 'DNSServerGroup'), - section(_('DNS Servers'), 'dhcp', 'DNSServer'), - ] - ), - ralph_item( - title=_('Licenses'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Licences'), 'licences', 'Licence'), - section(_('Types'), 'licences', 'LicenceType'), - section(_('Software'), 'licences', 'Software'), - ] - ), - ralph_item( - title=_('Intellectual Property'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Trade Marks'), 'trade_marks', 'TradeMark'), - section(_('Designs'), 'trade_marks', 'Design'), - section(_('Patents'), 'trade_marks', 'Patent'), - section(_('Utility Models'), 'trade_marks', 'UtilityModel'), - section(_('Domains'), 'domains', 'Domain'), - section(_('Contracts'), 'domains', 'DomainContract'), - section(_('Registrants'), 'domains', 'DomainRegistrant'), - section(_('Owners'), 'accounts', 'RalphUser'), - section(_('DNS Providers'), 'domains', 'DNSProvider'), - section(_('Domain Categories'), 'domains', 'DomainCategory'), - section(_('SSL Certificates'), - 'ssl_certificates', 'SSLCertificate') - ] - ), - ralph_item( - title=_('Supports'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Supports'), 'supports', 'Support'), - section(_('Types'), 'supports', 'SupportType'), - section(_('Assets supports'), 'supports', 'BaseObjectsSupport'), - ] - ), - ralph_item( - title=_('Reports'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - ralph_item( - title=_('Category model'), - url='category_model_report', - access_by_perms=( - 'accounts.can_view_extra_categorymodelreport' + tree( + "ralph_admin", + items=[ + ralph_item( + title=_("Data Center"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("All hosts"), "data_center", "DCHost"), + ralph_item( + title=_("DC Visualization"), + url="dc_view", + access_by_perms="accounts.can_view_extra_serverroomview", ), - ), - ralph_item( - title=_('Category model status'), - url='category_model__status_report', - access_by_perms=( - 'accounts.can_view_extra_categorymodelstatusreport' + section(_("Hardware"), "data_center", "DataCenterAsset"), + section(_("Virtual Servers"), "virtual", "VirtualServer"), + section(_("Clusters"), "data_center", "cluster"), + section(_("Data Centers"), "data_center", "DataCenter"), + section(_("Racks"), "data_center", "Rack"), + section(_("Rack accessories"), "data_center", "RackAccessory"), + section(_("accessories"), "data_center", "Accessory"), + section(_("Databases"), "data_center", "Database"), + section(_("Disk Shares"), "data_center", "DiskShare"), + section(_("Server Rooms"), "data_center", "ServerRoom"), + section(_("VIPs"), "data_center", "VIP"), + section(_("Preboots"), "deployment", "Preboot"), + section( + _("Preboot configuration"), "deployment", "PrebootConfiguration" ), - ), - ralph_item( - title=_('Manufacturer category model'), - url='manufactured_category_model_report', - access_by_perms=( - 'accounts.' - 'can_view_extra_manufacturercategorymodelreport' + section(_("Preboot files"), "deployment", "PrebootFile"), + ], + ), + ralph_item( + title=_("Cloud"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Cloud hosts"), "virtual", "CloudHost"), + section(_("Cloud projects"), "virtual", "CloudProject"), + section(_("Cloud flavors"), "virtual", "CloudFlavor"), + section(_("Cloud providers"), "virtual", "CloudProvider"), + section(_("Cloud images"), "virtual", "CloudImage"), + ], + ), + ralph_item( + title=_("Back Office"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Access Cards"), "access_cards", "AccessCard"), + section(_("Hardware"), "back_office", "backofficeasset"), + section(_("SIM Cards"), "sim_cards", "SIMCard"), + section(_("Accessory"), "accessories", "Accessory"), + ], + ), + ralph_item( + title=_("Networks"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Networks"), "networks", "network"), + section( + _("Network environments"), "networks", "networkenvironment" ), - ), - ralph_item( - title=_('Status model'), - url='status_model_report', - access_by_perms=( - 'accounts.can_view_extra_statusmodelreport' + section(_("Network kind"), "networks", "networkkind"), + section(_("IP Addresses"), "networks", "ipaddress"), + section(_("DHCP Servers"), "dhcp", "DHCPServer"), + section(_("DNS Server Groups"), "dhcp", "DNSServerGroup"), + section(_("DNS Servers"), "dhcp", "DNSServer"), + ], + ), + ralph_item( + title=_("Licenses"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Licences"), "licences", "Licence"), + section(_("Types"), "licences", "LicenceType"), + section(_("Software"), "licences", "Software"), + ], + ), + ralph_item( + title=_("Intellectual Property"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Trade Marks"), "trade_marks", "TradeMark"), + section(_("Designs"), "trade_marks", "Design"), + section(_("Patents"), "trade_marks", "Patent"), + section(_("Utility Models"), "trade_marks", "UtilityModel"), + section(_("Domains"), "domains", "Domain"), + section(_("Contracts"), "domains", "DomainContract"), + section(_("Registrants"), "domains", "DomainRegistrant"), + section(_("Owners"), "accounts", "RalphUser"), + section(_("DNS Providers"), "domains", "DNSProvider"), + section(_("Domain Categories"), "domains", "DomainCategory"), + section( + _("SSL Certificates"), "ssl_certificates", "SSLCertificate" ), - ), - ralph_item( - title=_('Asset - relations'), - url='asset-relations', - access_by_perms=( - 'accounts.can_view_extra_assetrelationsreport' + ], + ), + ralph_item( + title=_("Supports"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Supports"), "supports", "Support"), + section(_("Types"), "supports", "SupportType"), + section(_("Assets supports"), "supports", "BaseObjectsSupport"), + ], + ), + ralph_item( + title=_("Reports"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + ralph_item( + title=_("Category model"), + url="category_model_report", + access_by_perms=("accounts.can_view_extra_categorymodelreport"), ), - ), - ralph_item( - title=_('Licence - relations'), - url='licence-relations', - access_by_perms=( - 'accounts.can_view_extra_licencerelationsreport' + ralph_item( + title=_("Category model status"), + url="category_model__status_report", + access_by_perms=( + "accounts.can_view_extra_categorymodelstatusreport" + ), ), - ), - ralph_item( - title=_('Assets - supports'), - url='assets-supports', - access_by_perms=( - 'accounts.can_view_extra_assetsupportsreport' + ralph_item( + title=_("Manufacturer category model"), + url="manufactured_category_model_report", + access_by_perms=( + "accounts." "can_view_extra_manufacturercategorymodelreport" + ), ), - ), - ralph_item( - title=_('Failures'), - url='failures-report', - access_by_perms=( - 'accounts.can_view_extra_failurereport' + ralph_item( + title=_("Status model"), + url="status_model_report", + access_by_perms=("accounts.can_view_extra_statusmodelreport"), ), - ), - ] - ), - ralph_item( - title=_('Operations'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Changes'), 'operations', 'Change'), - section(_('Problems'), 'operations', 'Problem'), - section(_('Incidents'), 'operations', 'Incident'), - section(_('Failures'), 'operations', 'Failure'), - section(_('All'), 'operations', 'Operation'), - section(_('Types'), 'operations', 'OperationType'), - section(_('Statuses'), 'operations', 'OperationStatus'), - ] - ), - ralph_item( - title=_('Dashboards'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Dashboards'), 'dashboards', 'Dashboard'), - section(_('Graphs'), 'dashboards', 'Graph'), - ] - ), - ralph_item( - title=_('Settings'), - url='#', - url_as_pattern=False, - perms_mode_all=False, - children=[ - section(_('Asset model'), 'assets', 'AssetModel'), - section(_('Asset category'), 'assets', 'Category'), - section(_('Manufacturer'), 'assets', 'Manufacturer'), - section(_('Manufacturer Kind'), 'assets', 'Manufacturerkind'), - section(_('Business segment'), 'assets', 'BusinessSegment'), - section(_('Profit center'), 'assets', 'ProfitCenter'), - section(_('Service'), 'assets', 'Service'), - section(_('Environment'), 'assets', 'Environment'), - section(_('Budget info'), 'assets', 'BudgetInfo'), - section( - _('Service Environment'), 'assets', 'ServiceEnvironment' - ), - section( - _('Configuration modules'), 'assets', 'ConfigurationModule' - ), - section( - _('Configuration classes'), 'assets', 'ConfigurationClass' - ), - section(_('Asset holder'), 'assets', 'AssetHolder'), - section(_('Users list'), 'accounts', 'RalphUser'), - section(_('Groups list'), 'auth', 'Group'), - section(_('Regions'), 'accounts', 'Region'), - section(_('Access Zones'), 'access_cards', 'AccessZone'), - section(_('Transitions'), 'transitions', 'TransitionModel'), - section(_('Report template'), 'reports', 'Report'), - section(_('Custom fields'), 'custom_fields', 'CustomField'), - section(_('Warehouses'), 'back_office', 'warehouse'), - section( - _('Office Infrastructures'), - 'back_office', - 'officeinfrastructure' - ), - ] - ) - ]) + ralph_item( + title=_("Asset - relations"), + url="asset-relations", + access_by_perms=( + "accounts.can_view_extra_assetrelationsreport" + ), + ), + ralph_item( + title=_("Licence - relations"), + url="licence-relations", + access_by_perms=( + "accounts.can_view_extra_licencerelationsreport" + ), + ), + ralph_item( + title=_("Assets - supports"), + url="assets-supports", + access_by_perms=("accounts.can_view_extra_assetsupportsreport"), + ), + ralph_item( + title=_("Failures"), + url="failures-report", + access_by_perms=("accounts.can_view_extra_failurereport"), + ), + ], + ), + ralph_item( + title=_("Operations"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Changes"), "operations", "Change"), + section(_("Problems"), "operations", "Problem"), + section(_("Incidents"), "operations", "Incident"), + section(_("Failures"), "operations", "Failure"), + section(_("All"), "operations", "Operation"), + section(_("Types"), "operations", "OperationType"), + section(_("Statuses"), "operations", "OperationStatus"), + ], + ), + ralph_item( + title=_("Dashboards"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Dashboards"), "dashboards", "Dashboard"), + section(_("Graphs"), "dashboards", "Graph"), + ], + ), + ralph_item( + title=_("Settings"), + url="#", + url_as_pattern=False, + perms_mode_all=False, + children=[ + section(_("Asset model"), "assets", "AssetModel"), + section(_("Asset category"), "assets", "Category"), + section(_("Manufacturer"), "assets", "Manufacturer"), + section(_("Manufacturer Kind"), "assets", "Manufacturerkind"), + section(_("Business segment"), "assets", "BusinessSegment"), + section(_("Profit center"), "assets", "ProfitCenter"), + section(_("Service"), "assets", "Service"), + section(_("Environment"), "assets", "Environment"), + section(_("Budget info"), "assets", "BudgetInfo"), + section(_("Service Environment"), "assets", "ServiceEnvironment"), + section( + _("Configuration modules"), "assets", "ConfigurationModule" + ), + section(_("Configuration classes"), "assets", "ConfigurationClass"), + section(_("Asset holder"), "assets", "AssetHolder"), + section(_("Users list"), "accounts", "RalphUser"), + section(_("Groups list"), "auth", "Group"), + section(_("Regions"), "accounts", "Region"), + section(_("Access Zones"), "access_cards", "AccessZone"), + section(_("Transitions"), "transitions", "TransitionModel"), + section(_("Report template"), "reports", "Report"), + section(_("Custom fields"), "custom_fields", "CustomField"), + section(_("Warehouses"), "back_office", "warehouse"), + section( + _("Office Infrastructures"), + "back_office", + "officeinfrastructure", + ), + ], + ), + ], + ) ] -register_i18n_trees(['ralph_admin']) +register_i18n_trees(["ralph_admin"]) diff --git a/src/ralph/admin/templatetags/admin_change_list.py b/src/ralph/admin/templatetags/admin_change_list.py index 3117b206bf..d775854421 100644 --- a/src/ralph/admin/templatetags/admin_change_list.py +++ b/src/ralph/admin/templatetags/admin_change_list.py @@ -5,7 +5,7 @@ register = Library() -DOT = '.' +DOT = "." DOTS = DOT * 3 @@ -17,13 +17,10 @@ def admin_paginator_number(cl, i): Wraps every entry in
  • tag comparing to regular Django pagination. """ if i == DOT: - return mark_safe('
  • {}
  • '.format(DOTS)) + return mark_safe("
  • {}
  • ".format(DOTS)) elif i == cl.page_num: - return format_html( - '
  • {}
  • ', i + 1) + return format_html('
  • {}
  • ', i + 1) else: return format_html( - '
  • {}
  • ', - cl.get_query_string({PAGE_VAR: i}), - i + 1 + '
  • {}
  • ', cl.get_query_string({PAGE_VAR: i}), i + 1 ) diff --git a/src/ralph/admin/templatetags/dashboard_tags.py b/src/ralph/admin/templatetags/dashboard_tags.py index 9a1ff60d61..fa92384236 100644 --- a/src/ralph/admin/templatetags/dashboard_tags.py +++ b/src/ralph/admin/templatetags/dashboard_tags.py @@ -24,29 +24,22 @@ get_team_asset_acceptance_url, get_team_assets_to_accept, get_test_asset_acceptance_url, - get_test_assets_to_accept + get_test_assets_to_accept, ) from ralph.assets.models import BaseObject, Service, ServiceEnvironment from ralph.back_office.models import BackOfficeAsset -from ralph.data_center.models import ( - DataCenter, - DataCenterAsset, - Rack, - RackAccessory -) +from ralph.data_center.models import DataCenter, DataCenterAsset, Rack, RackAccessory register = Library() -COLORS = ['green', 'blue', 'purple', 'orange', 'red', 'pink'] +COLORS = ["green", "blue", "purple", "orange", "red", "pink"] def get_user_equipment_tile_data(user): return { - 'class': 'my-equipment', - 'label': _('My equipment'), - 'count': BackOfficeAsset.objects.filter( - Q(user=user) | Q(owner=user) - ).count(), - 'url': reverse('current_user_info'), + "class": "my-equipment", + "label": _("My equipment"), + "count": BackOfficeAsset.objects.filter(Q(user=user) | Q(owner=user)).count(), + "url": reverse("current_user_info"), } @@ -55,10 +48,10 @@ def get_user_equipment_to_accept_tile_data(user): if not assets_to_accept_count: return None return { - 'class': 'equipment-to-accept', - 'label': _('Hardware pick up'), - 'count': assets_to_accept_count, - 'url': get_acceptance_url(user), + "class": "equipment-to-accept", + "label": _("Hardware pick up"), + "count": assets_to_accept_count, + "url": get_acceptance_url(user), } @@ -67,10 +60,10 @@ def get_user_simcard_to_accept_tile_data(user): if not simcard_to_accept_count: return None return { - 'class': 'equipment-to-accept', - 'label': _('SIM Card pick up'), - 'count': simcard_to_accept_count, - 'url': get_simcard_acceptance_url(user), + "class": "equipment-to-accept", + "label": _("SIM Card pick up"), + "count": simcard_to_accept_count, + "url": get_simcard_acceptance_url(user), } @@ -79,10 +72,10 @@ def get_user_access_card_to_accept_tile_data(user): if not access_card_to_accept_count: return None return { - 'class': 'equipment-to-accept', - 'label': _('Access Card pick up'), - 'count': access_card_to_accept_count, - 'url': get_access_card_acceptance_url(user), + "class": "equipment-to-accept", + "label": _("Access Card pick up"), + "count": access_card_to_accept_count, + "url": get_access_card_acceptance_url(user), } @@ -91,10 +84,10 @@ def get_user_equipment_to_accept_loan_tile_data(user): if not assets_to_accept_count: return None return { - 'class': 'equipment-to-accept-loan', - 'label': _('Hardware loan'), - 'count': assets_to_accept_count, - 'url': get_loan_acceptance_url(user), + "class": "equipment-to-accept-loan", + "label": _("Hardware loan"), + "count": assets_to_accept_count, + "url": get_loan_acceptance_url(user), } @@ -103,10 +96,10 @@ def get_user_equipment_to_accept_return_tile_data(user): if not assets_to_accept_count: return None return { - 'class': 'equipment-to-accept-return', - 'label': _('Hardware return'), - 'count': assets_to_accept_count, - 'url': get_return_acceptance_url(user), + "class": "equipment-to-accept-return", + "label": _("Hardware return"), + "count": assets_to_accept_count, + "url": get_return_acceptance_url(user), } @@ -115,10 +108,10 @@ def get_user_team_equipment_to_accept_tile_data(user): if not assets_to_accept_count: return None return { - 'class': 'equipment-to-accept', - 'label': _('Team hardware pick up'), - 'count': assets_to_accept_count, - 'url': get_team_asset_acceptance_url(user), + "class": "equipment-to-accept", + "label": _("Team hardware pick up"), + "count": assets_to_accept_count, + "url": get_team_asset_acceptance_url(user), } @@ -127,110 +120,108 @@ def get_user_test_equipment_to_accept_tile_data(user): if not assets_to_accept_count: return None return { - 'class': 'equipment-to-accept', - 'label': _('Test hardware pick up'), - 'count': assets_to_accept_count, - 'url': get_test_asset_acceptance_url(user), + "class": "equipment-to-accept", + "label": _("Test hardware pick up"), + "count": assets_to_accept_count, + "url": get_test_asset_acceptance_url(user), } def get_available_space_in_data_centers(data_centers): - available = Rack.objects.filter( - server_room__data_center__in=data_centers, - require_position=True - ).values_list( - 'server_room__data_center__name' - ).annotate( - s=Sum('max_u_height') + available = ( + Rack.objects.filter( + server_room__data_center__in=data_centers, require_position=True + ) + .values_list("server_room__data_center__name") + .annotate(s=Sum("max_u_height")) ) return Counter(dict(available)) def get_used_space_in_data_centers(data_centers): - used_by_accessories = RackAccessory.objects.filter( - rack__server_room__data_center__in=data_centers, - ).values_list( - 'rack__server_room__data_center__name' - ).annotate( - s=Count('rack') + used_by_accessories = ( + RackAccessory.objects.filter( + rack__server_room__data_center__in=data_centers, + ) + .values_list("rack__server_room__data_center__name") + .annotate(s=Count("rack")) ) - used_by_assets = DataCenterAsset.objects.filter( - rack__server_room__data_center__in=data_centers, - model__has_parent=False, - rack__require_position=True - ).values_list( - 'rack__server_room__data_center__name' - ).annotate( - s=Sum('model__height_of_device') + used_by_assets = ( + DataCenterAsset.objects.filter( + rack__server_room__data_center__in=data_centers, + model__has_parent=False, + rack__require_position=True, + ) + .values_list("rack__server_room__data_center__name") + .annotate(s=Sum("model__height_of_device")) ) return Counter(dict(used_by_assets)) + Counter(dict(used_by_accessories)) -@register.inclusion_tag( - 'admin/templatetags/dc_capacity.html', takes_context=True -) -def dc_capacity(context, data_centers=None, size='big'): +@register.inclusion_tag("admin/templatetags/dc_capacity.html", takes_context=True) +def dc_capacity(context, data_centers=None, size="big"): user = context.request.user - if not user.has_perm('data_center.view_datacenter'): + if not user.has_perm("data_center.view_datacenter"): return {} color = cycle(COLORS) if not data_centers: data_centers = DataCenter.objects.all() if not isinstance(data_centers, Iterable): data_centers = [data_centers] - data_centers_mapper = dict(data_centers.values_list('name', 'id')) + data_centers_mapper = dict(data_centers.values_list("name", "id")) available_space = get_available_space_in_data_centers(data_centers) used_space = get_used_space_in_data_centers(data_centers) difference = dict(available_space - used_space) results = [] for name, value in sorted(difference.items()): capacity = 100 - (100 * value / available_space[name]) - tooltip = 'Free U: {} ({} in total)'.format( - available_space[name] - int(used_space[name]), - available_space[name] + tooltip = "Free U: {} ({} in total)".format( + available_space[name] - int(used_space[name]), available_space[name] ) - results.append({ - 'url': '{}#/dc/{}'.format( - reverse('dc_view'), data_centers_mapper[name] - ), - 'tooltip': tooltip, - 'size': size, - 'color': next(color), - 'dc': name, - 'capacity': int(capacity) - }) - return {'capacities': results} + results.append( + { + "url": "{}#/dc/{}".format( + reverse("dc_view"), data_centers_mapper[name] + ), + "tooltip": tooltip, + "size": size, + "color": next(color), + "dc": name, + "capacity": int(capacity), + } + ) + return {"capacities": results} -@register.inclusion_tag( - 'admin/templatetags/ralph_summary.html', takes_context=True -) +@register.inclusion_tag("admin/templatetags/ralph_summary.html", takes_context=True) def ralph_summary(context): user = context.request.user models = [ - 'data_center.DataCenterAsset', - 'back_office.BackOfficeAsset', - 'licences.Licence', - 'supports.Support', - 'domains.Domain', - 'accounts.RalphUser', + "data_center.DataCenterAsset", + "back_office.BackOfficeAsset", + "licences.Licence", + "supports.Support", + "domains.Domain", + "accounts.RalphUser", ] results = [] for model_name in models: - app, model = model_name.split('.') + app, model = model_name.split(".") model = apps.get_model(app, model) meta = model._meta - if not user.has_perm('{}.view_{}'.format(app, meta.model_name)): + if not user.has_perm("{}.view_{}".format(app, meta.model_name)): continue - results.append({ - 'label': meta.verbose_name_plural, - 'count': model.objects.count(), - 'class': slugify(meta.model_name), - 'icon': 'icon', - 'url': reverse('admin:{}_{}_changelist'.format( - meta.app_label, meta.model_name - )) - }) + results.append( + { + "label": meta.verbose_name_plural, + "count": model.objects.count(), + "class": slugify(meta.model_name), + "icon": "icon", + "url": reverse( + "admin:{}_{}_changelist".format(meta.app_label, meta.model_name) + ), + } + ) results.append(get_user_equipment_tile_data(user=user)) accept_tile_data = get_user_equipment_to_accept_tile_data(user=user) if accept_tile_data: @@ -238,54 +229,61 @@ def ralph_summary(context): accept_for_simcard_tile_data = get_user_simcard_to_accept_tile_data(user=user) # noqa if accept_for_simcard_tile_data: results.append(accept_for_simcard_tile_data) - accept_for_access_card_tile_data = get_user_access_card_to_accept_tile_data(user=user) # noqa + accept_for_access_card_tile_data = get_user_access_card_to_accept_tile_data( + user=user + ) # noqa if accept_for_access_card_tile_data: results.append(accept_for_access_card_tile_data) accept_for_loan_tile_data = get_user_equipment_to_accept_loan_tile_data(user=user) # noqa if accept_for_loan_tile_data: results.append(accept_for_loan_tile_data) - accept_for_return_tile_data = get_user_equipment_to_accept_return_tile_data(user=user) # noqa + accept_for_return_tile_data = get_user_equipment_to_accept_return_tile_data( + user=user + ) # noqa if accept_for_return_tile_data: results.append(accept_for_return_tile_data) - accept_for_team_asset_tile_data = get_user_team_equipment_to_accept_tile_data(user=user) # noqa + accept_for_team_asset_tile_data = get_user_team_equipment_to_accept_tile_data( + user=user + ) # noqa if accept_for_team_asset_tile_data: results.append(accept_for_team_asset_tile_data) - accept_for_test_asset_tile_data = get_user_test_equipment_to_accept_tile_data(user=user) # noqa + accept_for_test_asset_tile_data = get_user_test_equipment_to_accept_tile_data( + user=user + ) # noqa if accept_for_test_asset_tile_data: results.append(accept_for_test_asset_tile_data) - return {'results': results} + return {"results": results} -@register.inclusion_tag('admin/templatetags/my_services.html') +@register.inclusion_tag("admin/templatetags/my_services.html") def my_services(user): return { - 'services': Service.objects.prefetch_related( + "services": Service.objects.prefetch_related( Prefetch( - 'serviceenvironment_set', + "serviceenvironment_set", queryset=ServiceEnvironment.objects.prefetch_related( Prefetch( - 'baseobject_set', - queryset=BaseObject.objects.order_by('content_type_id') + "baseobject_set", + queryset=BaseObject.objects.order_by("content_type_id"), ) - ) + ), ), - 'serviceenvironment_set__environment', + "serviceenvironment_set__environment", ).filter(technical_owners=user, active=True), - 'user': user + "user": user, } -@register.inclusion_tag('admin/templatetags/objects_summary.html') +@register.inclusion_tag("admin/templatetags/objects_summary.html") def get_objects_summary(service_env, content_type_id, objects): from django.urls import reverse + content_type = ContentType.objects.get_for_id(content_type_id) opts = content_type.model_class()._meta - url = reverse( - 'admin:{}_{}_changelist'.format(opts.app_label, opts.model_name) - ) + url = reverse("admin:{}_{}_changelist".format(opts.app_label, opts.model_name)) return { - 'url': '{}?service_env={}'.format(url, service_env.id), - 'name': opts.verbose_name, - 'count': len(objects), + "url": "{}?service_env={}".format(url, service_env.id), + "name": opts.verbose_name, + "count": len(objects), } diff --git a/src/ralph/admin/templatetags/ralph_tags.py b/src/ralph/admin/templatetags/ralph_tags.py index 09a11667f6..e22d2949c8 100644 --- a/src/ralph/admin/templatetags/ralph_tags.py +++ b/src/ralph/admin/templatetags/ralph_tags.py @@ -6,7 +6,7 @@ from ralph.admin.helpers import ( get_content_type_for_model, get_field_by_relation_path, - get_value_by_relation_path + get_value_by_relation_path, ) from ralph.lib.transitions.models import TransitionsHistory @@ -14,17 +14,17 @@ @register.inclusion_tag( - 'admin/templatetags/download_attachment.html', takes_context=True + "admin/templatetags/download_attachment.html", takes_context=True ) def download_attachments(context): return { - 'attachments_to_download': context.request.session.pop( - 'attachments_to_download', [] + "attachments_to_download": context.request.session.pop( + "attachments_to_download", [] ) } -@register.inclusion_tag('admin/templatetags/tabs.html', takes_context=True) +@register.inclusion_tag("admin/templatetags/tabs.html", takes_context=True) def views_tabs(context, views, name=None, obj=None): """ Render extra views as tabs. @@ -32,28 +32,28 @@ def views_tabs(context, views, name=None, obj=None): result = [] if obj: for view in views: - codename = '{}.{}'.format( - obj._meta.app_label, view.permision_codename - ) + codename = "{}.{}".format(obj._meta.app_label, view.permision_codename) if context.request.user.has_perm(codename): result.append(view) else: result = views - return {'views': result, 'name': name, 'object': obj} + return {"views": result, "name": name, "object": obj} -@register.inclusion_tag('admin/search_form.html', takes_context=True) +@register.inclusion_tag("admin/search_form.html", takes_context=True) def contextual_search_form(context, search_url, search_fields, verbose_name): - context.update({ - 'search_url': search_url, - 'search_fields': search_fields, - 'search_var': SEARCH_VAR, - 'verbose_name': verbose_name.lower(), - }) + context.update( + { + "search_url": search_url, + "search_fields": search_fields, + "search_var": SEARCH_VAR, + "verbose_name": verbose_name.lower(), + } + ) return context -@register.inclusion_tag('admin/submit_line.html', takes_context=True) +@register.inclusion_tag("admin/submit_line.html", takes_context=True) def ralph_submit_row(context): """ Overriding the default templatetag Django and adding @@ -62,8 +62,8 @@ def ralph_submit_row(context): Return context. """ ctx = submit_row(context) - ctx['multi_add_url'] = context.get('multi_add_url', None) - ctx['multi_add_field'] = context.get('multi_add_field', None) + ctx["multi_add_url"] = context.get("multi_add_url", None) + ctx["multi_add_field"] = context.get("multi_add_field", None) return ctx @@ -91,7 +91,7 @@ def get_verbose_name(obj, name): return get_field_by_relation_path(obj, name).verbose_name -@register.inclusion_tag('admin/templatetags/transition_history.html') +@register.inclusion_tag("admin/templatetags/transition_history.html") def transition_history(obj): """ Display transition history for model. @@ -103,11 +103,10 @@ def transition_history(obj): {% transition_history object %} """ content_type = get_content_type_for_model(obj) - history = TransitionsHistory.objects.filter( - content_type=content_type, object_id=obj.pk - ).select_related('logged_user').order_by('-created') + history = ( + TransitionsHistory.objects.filter(content_type=content_type, object_id=obj.pk) + .select_related("logged_user") + .order_by("-created") + ) - return { - 'transitions_history': history, - 'transition_history_in_fieldset': True - } + return {"transitions_history": history, "transition_history_in_fieldset": True} diff --git a/src/ralph/admin/tests/test_m2m.py b/src/ralph/admin/tests/test_m2m.py index 2a61667105..03196d17c3 100644 --- a/src/ralph/admin/tests/test_m2m.py +++ b/src/ralph/admin/tests/test_m2m.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from datetime import date -from decimal import Decimal from django.test import RequestFactory, TestCase from django.urls import reverse @@ -13,19 +12,13 @@ class M2MInlineTest(ClientMixin, TestCase): def setUp(self): - self.foo1 = Foo.objects.create(bar='a') - self.foo2 = Foo.objects.create(bar='b') + self.foo1 = Foo.objects.create(bar="a") + self.foo2 = Foo.objects.create(bar="b") self.bar1 = Bar.objects.create( - name='Bar11', - date=date(2015, 3, 1), - price=Money('21.4', 'PLN'), - count=1 + name="Bar11", date=date(2015, 3, 1), price=Money("21.4", "PLN"), count=1 ) self.bar2 = Bar.objects.create( - name='Bar22', - date=date(2015, 3, 1), - price=Money('21.4', 'PLN'), - count=1 + name="Bar22", date=date(2015, 3, 1), price=Money("21.4", "PLN"), count=1 ) self.foo1.bars.add(self.bar1) self.foo1.bars.add(self.bar2) @@ -35,53 +28,53 @@ def setUp(self): def test_create_foo_with_bars(self): data = { - 'bar': 'c', - '_save': 'Save', - 'bars-TOTAL_FORMS': 1, - 'bars-INITIAL_FORMS': 0, - 'bars-MAX_NUM_FORMS': 0, - 'bars-0-name': 'Bar33', - 'bars-0-date': '2015-03-05', - 'bars-0-price_0': '10.10', - 'bars-0-price_1': 'PLN', - 'bars-0-count': '10', + "bar": "c", + "_save": "Save", + "bars-TOTAL_FORMS": 1, + "bars-INITIAL_FORMS": 0, + "bars-MAX_NUM_FORMS": 0, + "bars-0-name": "Bar33", + "bars-0-date": "2015-03-05", + "bars-0-price_0": "10.10", + "bars-0-price_1": "PLN", + "bars-0-count": "10", } - response = self.client.post(reverse('admin:tests_foo_add'), data) + response = self.client.post(reverse("admin:tests_foo_add"), data) self.assertEqual(response.status_code, 302) - foo = Foo.objects.get(bar='c') + foo = Foo.objects.get(bar="c") self.assertEqual(foo.bars.count(), 1) bar = foo.bars.all()[0] - self.assertEqual(bar.name, 'Bar33') + self.assertEqual(bar.name, "Bar33") def test_delete_assignment(self): data = { - 'bar': 'a', - '_save': 'Save', - 'bars-TOTAL_FORMS': 2, - 'bars-INITIAL_FORMS': 2, - 'bars-MAX_NUM_FORMS': 0, - 'bars-0-id': self.bar1.id, - 'bars-0-name': 'Bar11', - 'bars-0-date': '2015-03-01', - 'bars-0-price_0': '21.4', - 'bars-0-price_1': 'PLN', - 'bars-0-count': '1', - 'bars-0-DELETE': 'on', - 'bars-1-id': self.bar2.id, - 'bars-1-name': 'Bar33', # change here! - 'bars-1-date': '2016-06-06', # change here! - 'bars-1-price_0': '11', # change here! - 'bars-1-price_1': 'PLN', # change here! - 'bars-1-count': '11', # change here! + "bar": "a", + "_save": "Save", + "bars-TOTAL_FORMS": 2, + "bars-INITIAL_FORMS": 2, + "bars-MAX_NUM_FORMS": 0, + "bars-0-id": self.bar1.id, + "bars-0-name": "Bar11", + "bars-0-date": "2015-03-01", + "bars-0-price_0": "21.4", + "bars-0-price_1": "PLN", + "bars-0-count": "1", + "bars-0-DELETE": "on", + "bars-1-id": self.bar2.id, + "bars-1-name": "Bar33", # change here! + "bars-1-date": "2016-06-06", # change here! + "bars-1-price_0": "11", # change here! + "bars-1-price_1": "PLN", # change here! + "bars-1-count": "11", # change here! } response = self.client.post( - reverse('admin:tests_foo_change', args=(self.foo1.id,)), data + reverse("admin:tests_foo_change", args=(self.foo1.id,)), data ) self.assertEqual(response.status_code, 302) - foo = Foo.objects.get(bar='a') + foo = Foo.objects.get(bar="a") self.assertEqual(foo.bars.count(), 1) bar = foo.bars.all()[0] - self.assertEqual(bar.name, 'Bar33') + self.assertEqual(bar.name, "Bar33") self.assertEqual(bar.date, date(2016, 6, 6)) self.assertEqual(bar.price.amount, 11) self.assertEqual(bar.price.currency, PLN) diff --git a/src/ralph/admin/tests/test_menu.py b/src/ralph/admin/tests/test_menu.py index b117ac9b78..7c18b203be 100644 --- a/src/ralph/admin/tests/test_menu.py +++ b/src/ralph/admin/tests/test_menu.py @@ -5,4 +5,4 @@ class RalphMenuTest(TestCase): def test_menu_resync(self): - call_command('sitetree_resync_apps') + call_command("sitetree_resync_apps") diff --git a/src/ralph/admin/tests/test_templatetags.py b/src/ralph/admin/tests/test_templatetags.py index 9de23c9ec4..3e8cacf0b3 100644 --- a/src/ralph/admin/tests/test_templatetags.py +++ b/src/ralph/admin/tests/test_templatetags.py @@ -7,39 +7,39 @@ get_user_equipment_to_accept_loan_tile_data, get_user_equipment_to_accept_return_tile_data, get_user_equipment_to_accept_tile_data, - get_user_simcard_to_accept_tile_data) + get_user_simcard_to_accept_tile_data, +) class TestTemplatetags(TestCase): - - @patch('ralph.admin.templatetags.dashboard_tags.get_acceptance_url') - @patch('ralph.admin.templatetags.dashboard_tags.get_assets_to_accept') + @patch("ralph.admin.templatetags.dashboard_tags.get_acceptance_url") + @patch("ralph.admin.templatetags.dashboard_tags.get_assets_to_accept") def test_hardware_release_label(self, mocked_gata, mocked_gau): mocked_gata().count.return_value = 1 mocked_gau.return_value = "boo" ret = get_user_equipment_to_accept_tile_data(None) - assert ret['label'] == _('Hardware pick up') + assert ret["label"] == _("Hardware pick up") - @patch('ralph.admin.templatetags.dashboard_tags.get_loan_acceptance_url') - @patch('ralph.admin.templatetags.dashboard_tags.get_assets_to_accept_loan') + @patch("ralph.admin.templatetags.dashboard_tags.get_loan_acceptance_url") + @patch("ralph.admin.templatetags.dashboard_tags.get_assets_to_accept_loan") def test_hardware_loan_label(self, mocked_gatal, mocked_glau): mocked_gatal().count.return_value = 1 mocked_glau.return_value = "boo" ret = get_user_equipment_to_accept_loan_tile_data(None) - assert ret['label'] == _('Hardware loan') + assert ret["label"] == _("Hardware loan") - @patch('ralph.admin.templatetags.dashboard_tags.get_return_acceptance_url') - @patch('ralph.admin.templatetags.dashboard_tags.get_assets_to_accept_return') # noqa: + @patch("ralph.admin.templatetags.dashboard_tags.get_return_acceptance_url") + @patch("ralph.admin.templatetags.dashboard_tags.get_assets_to_accept_return") # noqa: def test_hardware_return_label(self, mocked_gatar, mocked_grau): mocked_gatar().count.return_value = 1 mocked_grau.return_value = "boo" ret = get_user_equipment_to_accept_return_tile_data(None) - assert ret['label'] == _('Hardware return') + assert ret["label"] == _("Hardware return") - @patch('ralph.admin.templatetags.dashboard_tags.get_simcard_acceptance_url') - @patch('ralph.admin.templatetags.dashboard_tags.get_simcards_to_accept') + @patch("ralph.admin.templatetags.dashboard_tags.get_simcard_acceptance_url") + @patch("ralph.admin.templatetags.dashboard_tags.get_simcards_to_accept") def test_simcard_release_label(self, mocked_gata, mocked_gau): mocked_gata().count.return_value = 1 mocked_gau.return_value = "boo" ret = get_user_simcard_to_accept_tile_data(None) - self.assertEqual(ret['label'], _('SIM Card pick up')) + self.assertEqual(ret["label"], _("SIM Card pick up")) diff --git a/src/ralph/admin/tests/tests_autocomplete.py b/src/ralph/admin/tests/tests_autocomplete.py index 271ed13c87..bf1aac4338 100644 --- a/src/ralph/admin/tests/tests_autocomplete.py +++ b/src/ralph/admin/tests/tests_autocomplete.py @@ -10,27 +10,20 @@ class AutocompleteSplitWordTest(TestCase): - def setUp(self): super().setUp() - self.user = UserFactory( - first_name='first_name_1', - last_name='last_name_1' - ) - UserFactory( - first_name='first_name_2', - last_name='last_name_2' - ) - self.region = RegionFactory(name='pl') - RegionFactory(name='de') + self.user = UserFactory(first_name="first_name_1", last_name="last_name_1") + UserFactory(first_name="first_name_2", last_name="last_name_2") + self.region = RegionFactory(name="pl") + RegionFactory(name="de") def test_or(self): autocomplete_list = AutocompleteList() autocomplete_list.model = RalphUser result = autocomplete_list.get_query_filters( RalphUser.objects.all(), - 'first_name_1 last_name_1', - ['username', 'first_name', 'last_name'] + "first_name_1 last_name_1", + ["username", "first_name", "last_name"], ) self.assertEqual(list(result), [self.user]) @@ -39,8 +32,8 @@ def test_or_empty(self): autocomplete_list.model = RalphUser result = autocomplete_list.get_query_filters( RalphUser.objects.all(), - 'first_name_1 last_name_2', - ['username', 'first_name', 'last_name'] + "first_name_1 last_name_2", + ["username", "first_name", "last_name"], ) self.assertEqual(len(result), 0) @@ -48,9 +41,7 @@ def test_not_or(self): autocomplete_list = AutocompleteList() autocomplete_list.model = Region result = autocomplete_list.get_query_filters( - Region.objects.all(), - 'pl', - ['name'] + Region.objects.all(), "pl", ["name"] ) self.assertEqual(list(result), [self.region]) @@ -58,24 +49,21 @@ def test_not_or_empty(self): autocomplete_list = AutocompleteList() autocomplete_list.model = Region result = autocomplete_list.get_query_filters( - Region.objects.all(), - 'pl de', - ['name'] + Region.objects.all(), "pl de", ["name"] ) self.assertEqual(len(result), 0) def test_autocomplete_endpoint_required_auth(self): - url = reverse( - 'autocomplete-list', - kwargs={ - 'app': 'assets', - 'field': 'service_env', - 'model': 'BaseObject' - } - ) + '?q=foobar' + url = ( + reverse( + "autocomplete-list", + kwargs={"app": "assets", "field": "service_env", "model": "BaseObject"}, + ) + + "?q=foobar" + ) resp = self.client.get(url) - target_params = urllib.parse.urlencode({'next': url}, safe='/') - expected_target = reverse('admin:login') + '?{}'.format(target_params) + target_params = urllib.parse.urlencode({"next": url}, safe="/") + expected_target = reverse("admin:login") + "?{}".format(target_params) self.assertRedirects(resp, expected_target) diff --git a/src/ralph/admin/tests/tests_fields.py b/src/ralph/admin/tests/tests_fields.py index 7aeecfb96d..bd5aeff503 100644 --- a/src/ralph/admin/tests/tests_fields.py +++ b/src/ralph/admin/tests/tests_fields.py @@ -8,162 +8,164 @@ class SimpleTestForm(MultivalueFormMixin, forms.Form): - multivalue_fields = ['sn', 'barcode', 'niw'] + multivalue_fields = ["sn", "barcode", "niw"] sn = MultilineField() barcode = MultilineField() niw = MultilineField(required=False) class OneRequiredTestForm(MultivalueFormMixin, forms.Form): - one_of_mulitvalue_required = ['sn', 'barcode'] - multivalue_fields = ['sn', 'barcode'] + one_of_mulitvalue_required = ["sn", "barcode"] + multivalue_fields = ["sn", "barcode"] sn = MultilineField() barcode = MultilineField() class TestAssetForm(MultivalueFormMixin, forms.ModelForm): - multivalue_fields = ['sn', 'barcode'] - one_of_mulitvalue_required = ['sn', 'barcode'] - sn = MultilineField('sn') - barcode = MultilineField('barcode') + multivalue_fields = ["sn", "barcode"] + one_of_mulitvalue_required = ["sn", "barcode"] + sn = MultilineField("sn") + barcode = MultilineField("barcode") class Meta: model = TestAsset - fields = ['hostname', 'sn', 'barcode'] + fields = ["hostname", "sn", "barcode"] class MultiValueFormTest(SimpleTestCase): def test_extend_empty_fields_at_the_end(self): data = { - 'sn': ['1', '2', '3'], - 'barcode': ['1'], + "sn": ["1", "2", "3"], + "barcode": ["1"], } form = SimpleTestForm({}) result = form.extend_empty_fields_at_the_end(data) - self.assertEqual(result, { - 'sn': ['1', '2', '3'], - 'barcode': ['1', '', ''], - 'niw': ['', '', ''], - }) + self.assertEqual( + result, + { + "sn": ["1", "2", "3"], + "barcode": ["1", "", ""], + "niw": ["", "", ""], + }, + ) def test_extend_empty_fields_at_the_end_with_empty_row(self): data = { - 'sn': ['1', '2', '3', ''], - 'barcode': ['1', '', '', ''], + "sn": ["1", "2", "3", ""], + "barcode": ["1", "", "", ""], } form = SimpleTestForm({}) result = form.extend_empty_fields_at_the_end(data) - self.assertEqual(result, { - 'sn': ['1', '2', '3'], - 'barcode': ['1', '', ''], - 'niw': ['', '', ''], - }) + self.assertEqual( + result, + { + "sn": ["1", "2", "3"], + "barcode": ["1", "", ""], + "niw": ["", "", ""], + }, + ) def test_works_for_single_value_each(self): data = { - 'sn': 'sn1', - 'barcode': 'bc1', - 'niw': 'niw1', + "sn": "sn1", + "barcode": "bc1", + "niw": "niw1", } form = SimpleTestForm(data) self.assertTrue(form.is_valid()) def test_works_for_multi_value_each(self): data = { - 'sn': 'sn1, sn2, sn3', - 'barcode': 'bc1, bc2, bc3', - 'niw': 'niw1, niw2, niw3', + "sn": "sn1, sn2, sn3", + "barcode": "bc1, bc2, bc3", + "niw": "niw1, niw2, niw3", } form = SimpleTestForm(data) self.assertTrue(form.is_valid()) def test_works_for_multi_value_with_empty_holes(self): data = { - 'sn': 'sn1, sn2, sn3', - 'barcode': 'bc1, bc2, bc3', - 'niw': 'niw1, , niw3', + "sn": "sn1, sn2, sn3", + "barcode": "bc1, bc2, bc3", + "niw": "niw1, , niw3", } form = SimpleTestForm(data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['niw'], ['niw1', '', 'niw3']) + self.assertEqual(form.cleaned_data["niw"], ["niw1", "", "niw3"]) def test_works_for_multi_value_with_empty_holes_at_the_end(self): data = { - 'sn': 'sn1, sn2, sn3', - 'barcode': 'bc1, bc2, bc3', - 'niw': 'niw1, ,', + "sn": "sn1, sn2, sn3", + "barcode": "bc1, bc2, bc3", + "niw": "niw1, ,", } form = SimpleTestForm(data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['niw'], ['niw1', '', '']) + self.assertEqual(form.cleaned_data["niw"], ["niw1", "", ""]) def test_works_for_multi_value_with_extension_to_longest_field(self): data = { - 'sn': 'sn1, sn2, sn3', - 'barcode': 'bc1, bc2, bc3', - 'niw': 'niw1', + "sn": "sn1, sn2, sn3", + "barcode": "bc1, bc2, bc3", + "niw": "niw1", } form = SimpleTestForm(data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['niw'], ['niw1', '', '']) + self.assertEqual(form.cleaned_data["niw"], ["niw1", "", ""]) def test_valid_when_different_count(self): - data = { - 'sn': 'sn1', - 'barcode': 'bc1, bc2', - 'niw': 'niw1, niw2' - } + data = {"sn": "sn1", "barcode": "bc1, bc2", "niw": "niw1, niw2"} form = SimpleTestForm(data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['sn'], ['sn1', '']) + self.assertEqual(form.cleaned_data["sn"], ["sn1", ""]) def test_not_valid_when_empty_multivalues(self): data = { - 'sn': '', - 'barcode': '', + "sn": "", + "barcode": "", } form = OneRequiredTestForm(data) self.assertFalse(form.is_valid()) def test_not_valid_when_none_multivalue_passed(self): data = { - 'sn': 'sn1,,sn3', - 'barcode': 'br1,,br3', + "sn": "sn1,,sn3", + "barcode": "br1,,br3", } form = OneRequiredTestForm(data) self.assertFalse(form.is_valid()) - self.assertIn('sn', form.errors) - self.assertIn('barcode', form.errors) + self.assertIn("sn", form.errors) + self.assertIn("barcode", form.errors) class MultilineFieldTest(SimpleTestCase): def test_field_works_for_single_value(self): field = MultilineField() - value_with_duplicates = '1' - self.assertEqual(field.clean(value_with_duplicates), ['1']) + value_with_duplicates = "1" + self.assertEqual(field.clean(value_with_duplicates), ["1"]) def test_field_works_for_multi_value(self): field = MultilineField() - value_with_duplicates = '1,2' - self.assertEqual(field.clean(value_with_duplicates), ['1', '2']) + value_with_duplicates = "1,2" + self.assertEqual(field.clean(value_with_duplicates), ["1", "2"]) def test_field_not_valid_when_duplicates(self): field = MultilineField(allow_duplicates=False) - value_with_duplicates = '1,1' + value_with_duplicates = "1,1" with self.assertRaises(ValidationError): field.clean(value_with_duplicates) def test_field_valid_when_duplicates_allowed(self): field = MultilineField(allow_duplicates=True) - value_with_duplicates = '1,1' - self.assertEqual(field.clean(value_with_duplicates), ['1', '1']) + value_with_duplicates = "1,1" + self.assertEqual(field.clean(value_with_duplicates), ["1", "1"]) def test_field_strips_whitespaces(self): field = MultilineField(allow_duplicates=True) - value_with_duplicates = ' 1 ' - self.assertEqual(field.clean(value_with_duplicates), ['1']) + value_with_duplicates = " 1 " + self.assertEqual(field.clean(value_with_duplicates), ["1"]) def test_field_allows_blank_elements(self): field = MultilineField(allow_duplicates=True) - value_with_empty = '1,,3' - self.assertEqual(field.clean(value_with_empty), ['1', '', '3']) + value_with_empty = "1,,3" + self.assertEqual(field.clean(value_with_empty), ["1", "", "3"]) diff --git a/src/ralph/admin/tests/tests_filters.py b/src/ralph/admin/tests/tests_filters.py index 25d5e1465e..cd7b46ff0b 100644 --- a/src/ralph/admin/tests/tests_filters.py +++ b/src/ralph/admin/tests/tests_filters.py @@ -19,22 +19,16 @@ RelatedFieldListFilter, TagsListFilter, TextListFilter, - TreeRelatedAutocompleteFilterWithDescendants + TreeRelatedAutocompleteFilterWithDescendants, ) from ralph.admin.sites import ralph_site from ralph.assets.tests.factories import ( ConfigurationClassFactory, - ConfigurationModuleFactory + ConfigurationModuleFactory, ) from ralph.data_center.admin import DataCenterAssetAdmin -from ralph.data_center.models.physical import ( - DataCenterAsset, - DataCenterAssetStatus -) -from ralph.data_center.tests.factories import ( - DataCenterAssetFactory, - RackFactory -) +from ralph.data_center.models.physical import DataCenterAsset, DataCenterAssetStatus +from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory from ralph.supports.admin import SupportAdmin from ralph.supports.models import Support from ralph.supports.tests.factories import SupportFactory @@ -43,40 +37,39 @@ class AdminFiltersTestCase(TestCase): - @classmethod def setUpClass(cls): super().setUpClass() - cls.conf_module1 = ConfigurationModuleFactory(name='abc') + cls.conf_module1 = ConfigurationModuleFactory(name="abc") cls.conf_module2 = ConfigurationModuleFactory(parent=cls.conf_module1) cls.conf_class = ConfigurationClassFactory(module=cls.conf_module2) cls.dca_1 = DataCenterAssetFactory( invoice_date=datetime.date(2015, 1, 1), - barcode='barcode_one', + barcode="barcode_one", status=DataCenterAssetStatus.new, ) - cls.dca_1.tags.add('tag_1') + cls.dca_1.tags.add("tag_1") cls.dca_2 = DataCenterAssetFactory( invoice_date=datetime.date(2015, 2, 1), - barcode='barcode_two', + barcode="barcode_two", status=DataCenterAssetStatus.liquidated, ) - cls.dca_2.management_ip = '10.20.30.40' - cls.dca_2.tags.add('tag_1') + cls.dca_2.management_ip = "10.20.30.40" + cls.dca_2.tags.add("tag_1") cls.dca_3 = DataCenterAssetFactory( invoice_date=datetime.date(2015, 3, 1), force_depreciation=True, status=DataCenterAssetStatus.used, ) - cls.dca_3.tags.add('tag1') - cls.dca_3.tags.add('tag2') + cls.dca_3.tags.add("tag1") + cls.dca_3.tags.add("tag2") cls.dca_4 = DataCenterAssetFactory( invoice_date=datetime.date(2014, 3, 1), rack=RackFactory(), configuration_path=cls.conf_class, ) - cls.dca_4.tags.add('tag1') + cls.dca_4.tags.add("tag1") cls.support_1 = SupportFactory(price=10) cls.support_2 = SupportFactory(price=100) @@ -87,17 +80,17 @@ def add_session_to_request(self, request): request.session.save() def test_date_format_to_human(self): - self.assertEqual('YYYY-MM-DD', date_format_to_human('%Y-%m-%d')) - self.assertEqual('YY-DD-MM', date_format_to_human('%y-%d-%m')) + self.assertEqual("YYYY-MM-DD", date_format_to_human("%Y-%m-%d")) + self.assertEqual("YY-DD-MM", date_format_to_human("%y-%d-%m")) def test_boolean_filter(self): boolean_filter = BooleanListFilter( - field=DataCenterAsset._meta.get_field('force_depreciation'), + field=DataCenterAsset._meta.get_field("force_depreciation"), request=None, - params={'force_depreciation': True}, + params={"force_depreciation": True}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='force_depreciation' + field_path="force_depreciation", ) queryset = boolean_filter.queryset(None, DataCenterAsset.objects.all()) @@ -105,24 +98,24 @@ def test_boolean_filter(self): def test_choices_filter(self): choices_filter = ChoicesListFilter( - field=DataCenterAsset._meta.get_field('status'), + field=DataCenterAsset._meta.get_field("status"), request=None, - params={'status': DataCenterAssetStatus.new}, + params={"status": DataCenterAssetStatus.new}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='status' + field_path="status", ) queryset = choices_filter.queryset(None, DataCenterAsset.objects.all()) self.assertEqual(2, queryset.count()) choices_filter = ChoicesListFilter( - field=DataCenterAsset._meta.get_field('status'), + field=DataCenterAsset._meta.get_field("status"), request=None, - params={'status': DataCenterAssetStatus.used}, + params={"status": DataCenterAssetStatus.used}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='status' + field_path="status", ) queryset = choices_filter.queryset(None, DataCenterAsset.objects.all()) @@ -130,12 +123,12 @@ def test_choices_filter(self): def test_text_filter(self): text_filter = TextListFilter( - field=DataCenterAsset._meta.get_field('barcode'), + field=DataCenterAsset._meta.get_field("barcode"), request=None, - params={'barcode': 'barcode_one'}, + params={"barcode": "barcode_one"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='barcode' + field_path="barcode", ) queryset = text_filter.queryset(None, DataCenterAsset.objects.all()) @@ -143,12 +136,12 @@ def test_text_filter(self): def test_text_filter_with_separator(self): text_filter = TextListFilter( - field=DataCenterAsset._meta.get_field('barcode'), + field=DataCenterAsset._meta.get_field("barcode"), request=None, - params={'barcode': 'barcode_one|barcode_two'}, + params={"barcode": "barcode_one|barcode_two"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='barcode' + field_path="barcode", ) queryset = text_filter.queryset(None, DataCenterAsset.objects.all()) @@ -156,12 +149,12 @@ def test_text_filter_with_separator(self): def test_text_filter_with_separator_and_whitespace(self): text_filter = TextListFilter( - field=DataCenterAsset._meta.get_field('barcode'), + field=DataCenterAsset._meta.get_field("barcode"), request=None, - params={'barcode': ' barcode_one | barcode_two'}, + params={"barcode": " barcode_one | barcode_two"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='barcode' + field_path="barcode", ) queryset = text_filter.queryset(None, DataCenterAsset.objects.all()) @@ -169,12 +162,12 @@ def test_text_filter_with_separator_and_whitespace(self): def test_text_filter_contains(self): text_filter = TextListFilter( - field=DataCenterAsset._meta.get_field('barcode'), + field=DataCenterAsset._meta.get_field("barcode"), request=None, - params={'barcode': 'one'}, + params={"barcode": "one"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='barcode' + field_path="barcode", ) queryset = text_filter.queryset(None, DataCenterAsset.objects.all()) @@ -183,7 +176,7 @@ def test_text_filter_contains(self): def test_tags_filter(self): tags_filter = TagsListFilter( request=None, - params={'tags': 'tag1 & tag2'}, + params={"tags": "tag1 & tag2"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, ) @@ -193,7 +186,7 @@ def test_tags_filter(self): tags_filter = TagsListFilter( request=None, - params={'tags': 'tag1'}, + params={"tags": "tag1"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, ) @@ -203,15 +196,15 @@ def test_tags_filter(self): def test_date_filter(self): datet_filter = DateListFilter( - field=DataCenterAsset._meta.get_field('invoice_date'), + field=DataCenterAsset._meta.get_field("invoice_date"), request=None, params={ - 'invoice_date__start': '2015-01-20', - 'invoice_date__end': '2015-04-01', + "invoice_date__start": "2015-01-20", + "invoice_date__end": "2015-04-01", }, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='invoice_date' + field_path="invoice_date", ) queryset = datet_filter.queryset(None, DataCenterAsset.objects.all()) @@ -219,15 +212,15 @@ def test_date_filter(self): def test_date_filter_start(self): datet_filter = DateListFilter( - field=DataCenterAsset._meta.get_field('invoice_date'), + field=DataCenterAsset._meta.get_field("invoice_date"), request=None, params={ - 'invoice_date__start': '2015-02-1', - 'invoice_date__end': '', + "invoice_date__start": "2015-02-1", + "invoice_date__end": "", }, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='invoice_date' + field_path="invoice_date", ) queryset = datet_filter.queryset(None, DataCenterAsset.objects.all()) @@ -235,15 +228,15 @@ def test_date_filter_start(self): def test_date_filter_end(self): datet_filter = DateListFilter( - field=DataCenterAsset._meta.get_field('invoice_date'), + field=DataCenterAsset._meta.get_field("invoice_date"), request=None, params={ - 'invoice_date__start': '', - 'invoice_date__end': '2015-02-20', + "invoice_date__start": "", + "invoice_date__end": "2015-02-20", }, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='invoice_date' + field_path="invoice_date", ) queryset = datet_filter.queryset(None, DataCenterAsset.objects.all()) @@ -251,14 +244,14 @@ def test_date_filter_end(self): def test_related_field(self): related_filter = RelatedFieldListFilter( - field=DataCenterAsset._meta.get_field('rack'), + field=DataCenterAsset._meta.get_field("rack"), request=None, params={ - 'rack': self.dca_4.rack.id, + "rack": self.dca_4.rack.id, }, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='rack' + field_path="rack", ) queryset = related_filter.queryset(None, DataCenterAsset.objects.all()) @@ -268,16 +261,16 @@ def test_tree_related_field_with_descendants(self): related_filter = TreeRelatedAutocompleteFilterWithDescendants( field=( DataCenterAsset._meta.get_field( - 'configuration_path' - ).remote_field.model._meta.get_field('module') + "configuration_path" + ).remote_field.model._meta.get_field("module") ), request=None, params={ - 'configuration_path__module': str(self.conf_module1.id), + "configuration_path__module": str(self.conf_module1.id), }, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, - field_path='configuration_path__module' + field_path="configuration_path__module", ) queryset = related_filter.queryset(None, DataCenterAsset.objects.all()) @@ -285,15 +278,15 @@ def test_tree_related_field_with_descendants(self): def test_decimal_filter(self): datet_filter = NumberListFilter( - field=Support._meta.get_field('price'), + field=Support._meta.get_field("price"), request=None, params={ - 'price__start': 0, - 'price__end': 200, + "price__start": 0, + "price__end": 200, }, model=Support, model_admin=SupportAdmin, - field_path='price' + field_path="price", ) queryset = datet_filter.queryset(None, Support.objects.all()) @@ -301,15 +294,15 @@ def test_decimal_filter(self): def test_decimal_filter_start(self): datet_filter = NumberListFilter( - field=Support._meta.get_field('price'), + field=Support._meta.get_field("price"), request=None, params={ - 'price__start': 50, - 'price__end': '', + "price__start": 50, + "price__end": "", }, model=Support, model_admin=SupportAdmin, - field_path='price' + field_path="price", ) queryset = datet_filter.queryset(None, Support.objects.all()) @@ -317,15 +310,15 @@ def test_decimal_filter_start(self): def test_decimal_filter_end(self): datet_filter = NumberListFilter( - field=Support._meta.get_field('price'), + field=Support._meta.get_field("price"), request=None, params={ - 'price__start': '', - 'price__end': 50, + "price__start": "", + "price__end": 50, }, model=Support, model_admin=SupportAdmin, - field_path='price' + field_path="price", ) queryset = datet_filter.queryset(None, Support.objects.all()) @@ -334,80 +327,74 @@ def test_decimal_filter_end(self): def test_liquidated_status_filter(self): liquidated_filter = LiquidatedStatusFilter( request=None, - params={'liquidated': '1'}, + params={"liquidated": "1"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, ) - queryset = liquidated_filter.queryset( - None, DataCenterAsset.objects.all() - ) + queryset = liquidated_filter.queryset(None, DataCenterAsset.objects.all()) self.assertEqual(4, queryset.count()) liquidated_filter = LiquidatedStatusFilter( request=None, - params={'liquidated': None}, + params={"liquidated": None}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, ) - queryset = liquidated_filter.queryset( - None, DataCenterAsset.objects.all() - ) + queryset = liquidated_filter.queryset(None, DataCenterAsset.objects.all()) self.assertEqual(3, queryset.count()) def test_filter_title(self): related_filter = RelatedFieldListFilter( - field=Car._meta.get_field('manufacturer'), + field=Car._meta.get_field("manufacturer"), request=None, params={ - 'manufacturer': 1, + "manufacturer": 1, }, model=Car, model_admin=CarAdmin, - field_path='manufacturer' + field_path="manufacturer", ) - self.assertEqual('test', related_filter.title) + self.assertEqual("test", related_filter.title) def test_is_not_autocomplete(self): list_filter = CarAdmin.list_filter - CarAdmin.list_filter = ['manufacturer'] - request = RequestFactory().get('/') + CarAdmin.list_filter = ["manufacturer"] + request = RequestFactory().get("/") request.user = UserFactory(is_superuser=True, is_staff=True) self.add_session_to_request(request) car_admin = CarAdmin(Car, ralph_site) change_list = car_admin.changelist_view(request) - filters = change_list.context_data['cl'].get_filters(request) + filters = change_list.context_data["cl"].get_filters(request) self.assertTrue(isinstance(filters[0][0], RelatedFieldListFilter)) CarAdmin.list_filter = list_filter def test_is_autocomplete(self): - request = RequestFactory().get('/') + request = RequestFactory().get("/") request.user = UserFactory(is_superuser=True, is_staff=True) self.add_session_to_request(request) car_admin = Car2Admin(Car2, ralph_site) change_list = car_admin.changelist_view(request) - filters = change_list.context_data['cl'].get_filters(request) + filters = change_list.context_data["cl"].get_filters(request) - self.assertTrue(isinstance( - filters[0][0], RelatedAutocompleteFieldListFilter) - ) + self.assertTrue(isinstance(filters[0][0], RelatedAutocompleteFieldListFilter)) def test_incorrect_value_related(self): - request = RequestFactory().get('/') + request = RequestFactory().get("/") # ugly hack from https://code.djangoproject.com/ticket/17971 - setattr(request, 'session', 'session') + setattr(request, "session", "session") messages = FallbackStorage(request) - setattr(request, '_messages', messages) + setattr(request, "_messages", messages) related_filter = RelatedAutocompleteFieldListFilter( - field=Car._meta.get_field('manufacturer'), + field=Car._meta.get_field("manufacturer"), request=request, params={ - 'manufacturer': 'string', + "manufacturer": "string", }, model=Car, model_admin=CarAdmin, - field_path='manufacturer' + field_path="manufacturer", ) with self.assertRaises(IncorrectLookupParameters): related_filter.queryset(request, Car.objects.all()) @@ -415,11 +402,9 @@ def test_incorrect_value_related(self): def test_ip_address_filter(self): ipaddress_filter = IPFilter( request=None, - params={'ip': '10.20.30.40'}, + params={"ip": "10.20.30.40"}, model=DataCenterAsset, model_admin=DataCenterAssetAdmin, ) - queryset = ipaddress_filter.queryset( - None, DataCenterAsset.objects.all() - ) + queryset = ipaddress_filter.queryset(None, DataCenterAsset.objects.all()) self.assertEqual(1, queryset.count()) diff --git a/src/ralph/admin/tests/tests_functional.py b/src/ralph/admin/tests/tests_functional.py index 57f466e9f4..8dc5c7a776 100644 --- a/src/ralph/admin/tests/tests_functional.py +++ b/src/ralph/admin/tests/tests_functional.py @@ -18,31 +18,33 @@ class ExtraListView(RalphListView, View): - label = 'Extra list view' - name = 'list' - url_name = 'extra_list_view' + label = "Extra list view" + name = "list" + url_name = "extra_list_view" class ExtraDetailView(RalphDetailView, View): - label = 'Extra detail view' - name = 'detail' - url_name = 'extra_detail_view' + label = "Extra detail view" + name = "detail" + url_name = "extra_detail_view" def new_test_view(klass, view_name=None): - view_name = view_name or 'test_view_{}'.format(new_test_view.counter) + view_name = view_name or "test_view_{}".format(new_test_view.counter) class TestView(klass): - label = 'Test view {}'.format(new_test_view.counter) + label = "Test view {}".format(new_test_view.counter) name = url_name = view_name - template_name = 'tests/foo/detail.html' + template_name = "tests/foo/detail.html" + new_test_view.counter += 1 return TestView + + new_test_view.counter = 0 class ExtraViewsTest(ReloadUrlsMixin, ClientMixin, TestCase): - def setUp(self): # noqa super(ExtraViewsTest, self).setUp() if ralph_site.is_registered(Foo): @@ -59,55 +61,54 @@ def test_dynamic_register_model_to_admin_panel(self): Dynamic register model to admin panel. """ self._register_model_in_admin(Foo) - response = self.client.get( - reverse('admin:tests_foo_changelist'), follow=True - ) + response = self.client.get(reverse("admin:tests_foo_changelist"), follow=True) self.assertEqual(response.status_code, 200) def test_extra_list_view_via_class_attr(self): """ Added extra view to list view by added to admin class. """ + class FooListAdmin(RalphAdmin): - list_views = [type('ExtraListView', (ExtraListView,), {})] + list_views = [type("ExtraListView", (ExtraListView,), {})] + self._register_model_in_admin(Foo, FooListAdmin) - response = self.client.get( - reverse('admin:tests_foo_changelist'), follow=True - ) + response = self.client.get(reverse("admin:tests_foo_changelist"), follow=True) self.assertEqual(response.status_code, 200) - self.assertEqual( - response.context['list_views'][0].label, ExtraListView.label - ) + self.assertEqual(response.context["list_views"][0].label, ExtraListView.label) def test_extra_change_view_via_class_attr(self): """ Added extra view to change view by added to admin class. """ - obj = Foo.objects.create(bar='test') + obj = Foo.objects.create(bar="test") class FooChangeAdmin(RalphAdmin): - change_views = [type('ExtraDetailView', (ExtraDetailView,), {})] + change_views = [type("ExtraDetailView", (ExtraDetailView,), {})] + self._register_model_in_admin(Foo, FooChangeAdmin) response = self.client.get( - reverse('admin:tests_foo_change', args=(obj.pk,)), follow=True + reverse("admin:tests_foo_change", args=(obj.pk,)), follow=True ) self.assertEqual(response.status_code, 200) self.assertEqual( - response.context['change_views'][0].label, ExtraDetailView.label + response.context["change_views"][0].label, ExtraDetailView.label ) def test_visit_extra_list_view(self): """ Visit extra list view. """ + class FooListAdmin(RalphAdmin): - list_views = [type('ExtraListView', (ExtraListView,), {})] + list_views = [type("ExtraListView", (ExtraListView,), {})] + self._register_model_in_admin(Foo, FooListAdmin) response = self.client.get( - reverse('admin:tests_foo_extra_list_view'), follow=True + reverse("admin:tests_foo_extra_list_view"), follow=True ) self.assertEqual(response.status_code, 200) @@ -115,15 +116,15 @@ def test_visit_extra_detail_view(self): """ Added extra view to list view by added to admin class. """ - obj = Foo.objects.create(bar='test') + obj = Foo.objects.create(bar="test") class FooListAdmin(RalphAdmin): - change_views = [type('ExtraDetailView', (ExtraDetailView,), {})] + change_views = [type("ExtraDetailView", (ExtraDetailView,), {})] + self._register_model_in_admin(Foo, FooListAdmin) response = self.client.get( - reverse('admin:tests_foo_extra_detail_view', args=(obj.pk,)), - follow=True + reverse("admin:tests_foo_extra_detail_view", args=(obj.pk,)), follow=True ) self.assertEqual(response.status_code, 200) @@ -138,34 +139,28 @@ class TestView(new_test_view(RalphListView)): pass self.reload_urls() - response = self.client.get( - reverse('admin:tests_foo_changelist'), follow=True - ) + response = self.client.get(reverse("admin:tests_foo_changelist"), follow=True) self.assertEqual(response.status_code, 200) - self.assertEqual( - response.context['list_views'][0].label, TestView.label - ) + self.assertEqual(response.context["list_views"][0].label, TestView.label) def test_extra_change_view_via_decorator(self): """ Register extra view by decorator. """ - obj = Foo.objects.create(bar='test') + obj = Foo.objects.create(bar="test") self._register_model_in_admin(Foo) @register_extra_view(Foo) class TestView(RalphDetailView, View): - label = 'Test view' - url_name = 'extra_detail_view' + label = "Test view" + url_name = "extra_detail_view" self.reload_urls() response = self.client.get( - reverse('admin:tests_foo_change', args=(obj.pk,)), follow=True + reverse("admin:tests_foo_change", args=(obj.pk,)), follow=True ) self.assertEqual(response.status_code, 200) - self.assertEqual( - response.context['change_views'][0].label, TestView.label - ) + self.assertEqual(response.context["change_views"][0].label, TestView.label) def test_register_decorator_raise_value_error_incorrect_view_type(self): """ @@ -173,9 +168,10 @@ def test_register_decorator_raise_value_error_incorrect_view_type(self): """ self._register_model_in_admin(Foo) with self.assertRaises(ValueError): + @register_extra_view(Foo) class TestView(RalphListView): - _type = 'incorrect_type' + _type = "incorrect_type" def test_register_decorator_raise_value_error_incorrect_target_view(self): """ @@ -183,6 +179,7 @@ def test_register_decorator_raise_value_error_incorrect_target_view(self): """ self._register_model_in_admin(Foo) with self.assertRaises(ValueError): + @register_extra_view(Foo) class TestView(View): pass @@ -191,57 +188,46 @@ def test_many_tabs_link(self): """ Test links in tabs. """ - obj = Foo.objects.create(bar='test') - endpoints = [ - (RalphDetailView, 'test_url_1'), (RalphDetailView, 'test_url_2') - ] + obj = Foo.objects.create(bar="test") + endpoints = [(RalphDetailView, "test_url_1"), (RalphDetailView, "test_url_2")] views = [new_test_view(klass, name) for klass, name in endpoints] class FooAdmin(RalphAdmin): change_views = views + self._register_model_in_admin(Foo, FooAdmin) response = self.client.get( - reverse('admin:tests_foo_change', args=(obj.pk,)), follow=True + reverse("admin:tests_foo_change", args=(obj.pk,)), follow=True ) - tabs = response.context['change_views'] + tabs = response.context["change_views"] for tab in tabs: resp = self.client.get( - reverse(tab.url_with_namespace, args=[obj.pk, ]) + reverse( + tab.url_with_namespace, + args=[ + obj.pk, + ], + ) ) self.assertEqual(resp.status_code, 200) @ddt class ChangeListTest(TestCase): - def setUp(self): super().setUp() - manufacturer = TestManufacturer.objects.create( - name='test', country='pl' - ) - TestManufacturer.objects.create( - name='test2', country='pl2' - ) - Car.objects.create( - year=2015, - name='test', - manufacturer=manufacturer - ) + manufacturer = TestManufacturer.objects.create(name="test", country="pl") + TestManufacturer.objects.create(name="test2", country="pl2") + Car.objects.create(year=2015, name="test", manufacturer=manufacturer) Car.objects.create( - year=2014, - name='AutotompleteTest 2', - manufacturer=manufacturer + year=2014, name="AutotompleteTest 2", manufacturer=manufacturer ) Car.objects.create( - year=2015, - name='AutotompleteTest', - manufacturer=manufacturer + year=2015, name="AutotompleteTest", manufacturer=manufacturer ) - def _change_list_factory( - self, model, model_admin, request, list_display=None - ): + def _change_list_factory(self, model, model_admin, request, list_display=None): return RalphChangeList( date_hierarchy=model_admin.date_hierarchy, list_display=list_display or model_admin.list_display, @@ -260,14 +246,12 @@ def _change_list_factory( def _get_ordering_list(self, model, model_admin, params, list_display): from django.contrib.admin.views.main import ORDER_VAR - get_params = '{}={}'.format(ORDER_VAR, '.'.join(map(str, params))) - request = RequestFactory().get('/?' + get_params) + + get_params = "{}={}".format(ORDER_VAR, ".".join(map(str, params))) + request = RequestFactory().get("/?" + get_params) request.user = UserFactory() cl = self._change_list_factory( - model=Car, - model_admin=CarAdmin, - request=request, - list_display=list_display + model=Car, model_admin=CarAdmin, request=request, list_display=list_display ) return cl.get_ordering(request, model.objects.all()) @@ -275,100 +259,79 @@ def _get_ordering_list(self, model, model_admin, params, list_display): @data( ( [1], - ['pk', 'name', 'manufacturer'], - ['name', '-pk'], + ["pk", "name", "manufacturer"], + ["name", "-pk"], ), ( [1, 2], - ['pk', 'name', 'manufacturer'], - ['name', 'manufacturer__name', 'manufacturer__country', '-pk'], + ["pk", "name", "manufacturer"], + ["name", "manufacturer__name", "manufacturer__country", "-pk"], ), ( [-1, -2], - ['pk', 'name', 'manufacturer'], - [ - '-name', '-manufacturer__name', '-manufacturer__country', - '-pk' - ], + ["pk", "name", "manufacturer"], + ["-name", "-manufacturer__name", "-manufacturer__country", "-pk"], ), ( [-1, 2, 3], - ['pk', 'name', 'year', 'manufacturer'], - [ - '-name', 'year', 'manufacturer__name', - 'manufacturer__country', '-pk' - ], + ["pk", "name", "year", "manufacturer"], + ["-name", "year", "manufacturer__name", "manufacturer__country", "-pk"], ), ( [-1, 3, 2], - ['pk', 'name', 'year', 'manufacturer'], - [ - '-name', 'manufacturer__name', 'manufacturer__country', - 'year', '-pk' - ], + ["pk", "name", "year", "manufacturer"], + ["-name", "manufacturer__name", "manufacturer__country", "year", "-pk"], ), ( [3, 2, 1], - ['pk', 'name', 'year', 'manufacturer'], - [ - 'manufacturer__name', 'manufacturer__country', 'year', - 'name', '-pk' - ], + ["pk", "name", "year", "manufacturer"], + ["manufacturer__name", "manufacturer__country", "year", "name", "-pk"], ), ( [2, 1, 0], - ['name', 'year', 'manufacturer'], - [ - 'manufacturer__name', 'manufacturer__country', 'year', - 'name', '-pk' - ], + ["name", "year", "manufacturer"], + ["manufacturer__name", "manufacturer__country", "year", "name", "-pk"], ), ( [1, 2, 0], - ['name', 'year', 'manufacturer'], - [ - 'year', 'manufacturer__name', 'manufacturer__country', - 'name', '-pk' - ], + ["name", "year", "manufacturer"], + ["year", "manufacturer__name", "manufacturer__country", "name", "-pk"], ), ) def test_sort_related(self, ordering_params, list_display, expected_ordering): ordering = self._get_ordering_list( - Car, CarAdmin, ordering_params, list_display, + Car, + CarAdmin, + ordering_params, + list_display, ) self.assertEqual(expected_ordering, ordering) def test_get_queryset_autocomplete(self): - request = RequestFactory().get('/car', data={IS_POPUP_VAR: 1}) + request = RequestFactory().get("/car", data={IS_POPUP_VAR: 1}) change_list = self._change_list_factory( - model=Car, - model_admin=CarAdmin, - request=request, - list_display=['id'] + model=Car, model_admin=CarAdmin, request=request, list_display=["id"] ) resutlt = change_list.get_queryset(request) self.assertEqual(len(resutlt), 2) def test_get_queryset_aucotomplete_search(self): - request = RequestFactory().get('/car', data={ - IS_POPUP_VAR: 1, SEARCH_VAR: 'autotompletetest'} + request = RequestFactory().get( + "/car", data={IS_POPUP_VAR: 1, SEARCH_VAR: "autotompletetest"} ) change_list = self._change_list_factory( - model=Car, - model_admin=CarAdmin, - request=request, - list_display=['id'] + model=Car, model_admin=CarAdmin, request=request, list_display=["id"] ) resutlt = change_list.get_queryset(request) self.assertEqual(len(resutlt), 1) def test_get_queryset(self): - request = RequestFactory().get('/manufacturer', data={IS_POPUP_VAR: 1}) + request = RequestFactory().get("/manufacturer", data={IS_POPUP_VAR: 1}) change_list = self._change_list_factory( model=TestManufacturer, model_admin=ManufacturerAdmin, request=request, - list_display=['id'] + list_display=["id"], ) resutlt = change_list.get_queryset(request) self.assertEqual(len(resutlt), 2) diff --git a/src/ralph/admin/tests/tests_helpers.py b/src/ralph/admin/tests/tests_helpers.py index 64c7369266..4ec3352057 100644 --- a/src/ralph/admin/tests/tests_helpers.py +++ b/src/ralph/admin/tests/tests_helpers.py @@ -8,7 +8,7 @@ generate_html_link, get_content_type_for_model, get_field_by_relation_path, - getattr_dunder + getattr_dunder, ) from ralph.assets.models.assets import Asset, Manufacturer from ralph.assets.models.base import BaseObject @@ -17,51 +17,44 @@ @ddt class ModelFieldsTestCase(TestCase): def test_return_ok_when_simply_field(self): - field_name = 'barcode' + field_name = "barcode" found = get_field_by_relation_path(Asset, field_name) self.assertEqual(found, Asset._meta.get_field(field_name)) def test_return_ok_when_long_path(self): - found = get_field_by_relation_path(Asset, 'model__manufacturer__name') - self.assertEqual(found, Manufacturer._meta.get_field('name')) + found = get_field_by_relation_path(Asset, "model__manufacturer__name") + self.assertEqual(found, Manufacturer._meta.get_field("name")) def test_raise_exception_when_no_field(self): - fake_field = 'device_info__fortunately_unexisting_deprecated_field' + fake_field = "device_info__fortunately_unexisting_deprecated_field" with self.assertRaises(FieldDoesNotExist): - found = get_field_by_relation_path(Asset, fake_field) + get_field_by_relation_path(Asset, fake_field) def test_getattr_dunder(self): """getattr_dunder works recursively""" - class A(): + class A: pass a = A() a.b = A() - a.b.name = 'spam' - self.assertEqual(getattr_dunder(a, 'b__name'), 'spam') + a.b.name = "spam" + self.assertEqual(getattr_dunder(a, "b__name"), "spam") @unpack - @data( - (BaseObject, Asset), - (Manufacturer, Manufacturer) - ) + @data((BaseObject, Asset), (Manufacturer, Manufacturer)) def test_get_content_type_for_model(self, expected_model, model): self.assertEqual( ContentType.objects.get_for_model(expected_model), - get_content_type_for_model(model) + get_content_type_for_model(model), ) class GenerateLinkTest(TestCase): - def test_generate_html_link(self): url = generate_html_link( - 'http://test.com/', - label='Name', - params={'param': 1}, - ) - self.assertEqual( - url, - 'Name' + "http://test.com/", + label="Name", + params={"param": 1}, ) + self.assertEqual(url, 'Name') diff --git a/src/ralph/admin/tests/tests_multiadd.py b/src/ralph/admin/tests/tests_multiadd.py index e011a678ce..427f97eb11 100644 --- a/src/ralph/admin/tests/tests_multiadd.py +++ b/src/ralph/admin/tests/tests_multiadd.py @@ -13,200 +13,160 @@ class MultiAddTest(ClientMixin, TestCase): - def setUp(self): # noqa super().setUp() self.login_as_user() self.bo_admin = BackOfficeAssetAdmin( - model=BackOfficeAsset, - admin_site=ralph_site + model=BackOfficeAsset, admin_site=ralph_site ) self.dc_admin = BackOfficeAssetAdmin( - model=DataCenterAsset, - admin_site=ralph_site + model=DataCenterAsset, admin_site=ralph_site ) self.bo_1 = BackOfficeAssetFactory() - self.dc_1 = DataCenterAssetFactory(sn='12345') + self.dc_1 = DataCenterAssetFactory(sn="12345") def tests_multi_add_bo(self): post_data = { - 'sn': 'sn|sn2', - 'barcode': 'barcode,barcode2', - 'imei': '990000862471854\n990000862471855' + "sn": "sn|sn2", + "barcode": "barcode,barcode2", + "imei": "990000862471854\n990000862471855", } response = self.client.post( - reverse( - self.bo_admin.get_url_name(), - args=[self.bo_1.pk] - ), + reverse(self.bo_admin.get_url_name(), args=[self.bo_1.pk]), post_data, - follow=True + follow=True, ) self.assertEqual(response.status_code, 200) self.assertEqual(BackOfficeAsset.objects.count(), 3) result = BackOfficeAsset.objects.filter( - sn='sn', - barcode='barcode', - imei='990000862471854' + sn="sn", barcode="barcode", imei="990000862471854" ).count() self.assertEqual(result, 1) def test_multi_add_dc_with_not_required_field(self): post_data = { - 'sn': 'dc_sn,dc_sn2', - 'barcode': 'dc_barcode,dc_barcode2', - 'position': '1,2', - 'niw': '', + "sn": "dc_sn,dc_sn2", + "barcode": "dc_barcode,dc_barcode2", + "position": "1,2", + "niw": "", } response = self.client.post( - reverse( - self.dc_admin.get_url_name(), - args=[self.dc_1.pk] - ), + reverse(self.dc_admin.get_url_name(), args=[self.dc_1.pk]), post_data, - follow=True + follow=True, ) self.assertEqual(response.status_code, 200) self.assertEqual(DataCenterAsset.objects.count(), 3) result = DataCenterAsset.objects.filter( - sn='dc_sn', - barcode='dc_barcode', + sn="dc_sn", + barcode="dc_barcode", ).count() self.assertEqual(result, 1) def test_multi_add_is_empty_field(self): post_data = { - 'sn': 'dc_sn,dc_sn2', - 'barcode': '', - 'position': '1,2', - 'niw': '', + "sn": "dc_sn,dc_sn2", + "barcode": "", + "position": "1,2", + "niw": "", } response = self.client.post( - reverse( - self.dc_admin.get_url_name(), - args=[self.dc_1.pk] - ), + reverse(self.dc_admin.get_url_name(), args=[self.dc_1.pk]), post_data, - follow=True + follow=True, ) self.assertEqual(response.status_code, 200) self.assertEqual(DataCenterAsset.objects.count(), 3) def test_multi_add_smaller_number_of_lines(self): post_data = { - 'sn': 'dc_sn,dc_sn2', - 'barcode': 'barcode', - 'position': '1,2', - 'niw': '', + "sn": "dc_sn,dc_sn2", + "barcode": "barcode", + "position": "1,2", + "niw": "", } response = self.client.post( - reverse( - self.dc_admin.get_url_name(), - args=[self.dc_1.pk] - ), + reverse(self.dc_admin.get_url_name(), args=[self.dc_1.pk]), post_data, - follow=True + follow=True, ) self.assertEqual(response.status_code, 200) self.assertEqual(DataCenterAsset.objects.count(), 3) def test_multi_add_duplicate_sn(self): post_data = { - 'sn': 'dc_sn,dc_sn', - 'barcode': 'barcode,barcode2', - 'position': '1,2', - 'niw': '', + "sn": "dc_sn,dc_sn", + "barcode": "barcode,barcode2", + "position": "1,2", + "niw": "", } response = self.client.post( - reverse( - self.dc_admin.get_url_name(), - args=[self.dc_1.pk] - ), + reverse(self.dc_admin.get_url_name(), args=[self.dc_1.pk]), post_data, - follow=True - ) - self.assertFormError( - response, - 'form', - 'sn', - 'There are duplicates in field.' + follow=True, ) + self.assertFormError(response, "form", "sn", "There are duplicates in field.") def test_multi_add_barcode_and_sn_empty(self): post_data = { - 'sn': 'dc_sn,,dc_sn2', - 'barcode': 'barcode,,barcode2', - 'position': '1,2,3', - 'niw': '', + "sn": "dc_sn,,dc_sn2", + "barcode": "barcode,,barcode2", + "position": "1,2,3", + "niw": "", } response = self.client.post( - reverse( - self.dc_admin.get_url_name(), - args=[self.dc_1.pk] - ), + reverse(self.dc_admin.get_url_name(), args=[self.dc_1.pk]), post_data, - follow=True + follow=True, ) self.assertFormError( - response, - 'form', - 'sn', - 'Fill at least on of sn,barcode in each row' + response, "form", "sn", "Fill at least on of sn,barcode in each row" ) def test_multi_add_is_sn_exists(self): post_data = { - 'sn': self.dc_1.sn, - 'barcode': 'barcode', - 'position': '1', - 'niw': '', + "sn": self.dc_1.sn, + "barcode": "barcode", + "position": "1", + "niw": "", } response = self.client.post( - reverse( - self.dc_admin.get_url_name(), - args=[self.dc_1.pk] - ), + reverse(self.dc_admin.get_url_name(), args=[self.dc_1.pk]), post_data, - follow=True + follow=True, ) self.assertFormError( response, - 'form', - 'sn', - ( - 'Following items already exist: ' - '{}' - ).format(reverse( - 'admin:data_center_datacenterasset_change', args=[self.dc_1.pk] - ), self.dc_1.pk) + "form", + "sn", + ("Following items already exist: " '{}').format( + reverse( + "admin:data_center_datacenterasset_change", args=[self.dc_1.pk] + ), + self.dc_1.pk, + ), ) - @override_settings(MULTIADD_DATA_CENTER_ASSET_FIELDS=[ - {'field': 'sn', 'allow_duplicates': False}, - {'field': 'barcode', 'allow_duplicates': False}, - {'field': 'position', 'allow_duplicates': True}, - {'field': 'niw', 'allow_duplicates': False}, - ]) + @override_settings( + MULTIADD_DATA_CENTER_ASSET_FIELDS=[ + {"field": "sn", "allow_duplicates": False}, + {"field": "barcode", "allow_duplicates": False}, + {"field": "position", "allow_duplicates": True}, + {"field": "niw", "allow_duplicates": False}, + ] + ) def tests_multi_add_validation_integer(self): post_data = { - 'sn': 'sn5', - 'barcode': 'barcode5', - 'position': 'string', - 'niw': '', + "sn": "sn5", + "barcode": "barcode5", + "position": "string", + "niw": "", } response = self.client.post( - reverse( - self.dc_admin.get_url_name(), - args=[self.dc_1.pk] - ), + reverse(self.dc_admin.get_url_name(), args=[self.dc_1.pk]), post_data, - follow=True - ) - self.assertFormError( - response, - 'form', - 'position', - 'Enter a valid number.' + follow=True, ) + self.assertFormError(response, "form", "position", "Enter a valid number.") diff --git a/src/ralph/admin/tests/tests_tags.py b/src/ralph/admin/tests/tests_tags.py index e14ac8d47f..564b1e80ab 100644 --- a/src/ralph/admin/tests/tests_tags.py +++ b/src/ralph/admin/tests/tests_tags.py @@ -13,23 +13,22 @@ class RalphTagsTest(TestCase): - def setUp(self): super().setUp() user = UserFactory() back_office = BackOfficeAssetFactory() - content_type=ContentType.objects.get_for_model(BackOfficeAsset) + content_type = ContentType.objects.get_for_model(BackOfficeAsset) content = str.encode(str(random.random())) attachment = Attachment.objects.create( - file=SimpleUploadedFile('test', content), + file=SimpleUploadedFile("test", content), uploaded_by=user, ) self.history = TransitionsHistory.objects.create( - transition_name='test', + transition_name="test", content_type=content_type, - source='new', - target='used', + source="new", + target="used", object_id=back_office.pk, logged_user=user, - attachment=attachment + attachment=attachment, ) diff --git a/src/ralph/admin/tests/tests_views.py b/src/ralph/admin/tests/tests_views.py index 404ff3322b..3075d38d4b 100644 --- a/src/ralph/admin/tests/tests_views.py +++ b/src/ralph/admin/tests/tests_views.py @@ -13,138 +13,137 @@ from ralph.tests.models import Foo FACTORY_MAP = { - 'django.contrib.auth.models.Group': 'ralph.accounts.tests.factories.GroupFactory', # noqa - 'ralph.accessories.models.Accessory': 'ralph.accessories.tests.factories.AccessoryFactory', # noqa - 'ralph.access_cards.models.AccessCard': 'ralph.access_cards.tests.factories.AccessCardFactory', # noqa - 'ralph.access_cards.models.AccessZone': 'ralph.access_cards.tests.factories.AccessZoneFactory', # noqa - 'ralph.accounts.models.RalphUser': 'ralph.accounts.tests.factories.UserFactory', # noqa - 'ralph.accounts.models.Region': 'ralph.accounts.tests.factories.RegionFactory', # noqa - 'ralph.accounts.models.Team': 'ralph.accounts.tests.factories.TeamFactory', - 'ralph.assets.models.assets.AssetHolder': 'ralph.assets.tests.factories.AssetHolderFactory', # noqa - 'ralph.assets.models.assets.AssetModel': 'ralph.assets.tests.factories.BackOfficeAssetModelFactory', # noqa - 'ralph.assets.models.assets.BudgetInfo': 'ralph.assets.tests.factories.BudgetInfoFactory', # noqa - 'ralph.assets.models.assets.BusinessSegment': 'ralph.assets.tests.factories.BusinessSegmentFactory', # noqa - 'ralph.assets.models.assets.Category': 'ralph.assets.tests.factories.CategoryFactory', # noqa - 'ralph.assets.models.assets.Environment': 'ralph.assets.tests.factories.EnvironmentFactory', # noqa - 'ralph.assets.models.assets.Manufacturer': 'ralph.assets.tests.factories.ManufacturerFactory', # noqa - 'ralph.assets.models.assets.ManufacturerKind': 'ralph.assets.tests.factories.ManufacturerKindFactory', # noqa - 'ralph.assets.models.assets.ProfitCenter': 'ralph.assets.tests.factories.ProfitCenterFactory', # noqa - 'ralph.assets.models.assets.Service': 'ralph.assets.tests.factories.ServiceFactory', # noqa - 'ralph.assets.models.assets.ServiceEnvironment': 'ralph.assets.tests.factories.ServiceEnvironmentFactory', # noqa - 'ralph.assets.models.base.BaseObject': 'ralph.assets.tests.factories.BaseObjectFactory', # noqa - 'ralph.assets.models.components.ComponentModel': 'ralph.assets.tests.factories.ComponentModelFactory', # noqa - 'ralph.assets.models.components.Disk': 'ralph.assets.tests.factories.DiskFactory', # noqa - 'ralph.assets.models.components.Ethernet': 'ralph.assets.tests.factories.EthernetFactory', # noqa - 'ralph.assets.models.components.FibreChannelCard': 'ralph.assets.tests.factories.FibreChannelCardFactory', # noqa - 'ralph.assets.models.components.Memory': 'ralph.assets.tests.factories.MemoryFactory', # noqa - 'ralph.assets.models.components.Processor': 'ralph.assets.tests.factories.ProcessorFactory', # noqa - 'ralph.assets.models.configuration.ConfigurationClass': 'ralph.assets.tests.factories.ConfigurationClassFactory', # noqa - 'ralph.assets.models.configuration.ConfigurationModule': 'ralph.assets.tests.factories.ConfigurationModuleFactory', # noqa - 'ralph.back_office.models.BackOfficeAsset': 'ralph.back_office.tests.factories.BackOfficeAssetFactory', # noqa - 'ralph.back_office.models.OfficeInfrastructure': 'ralph.back_office.tests.factories.OfficeInfrastructureFactory', # noqa - 'ralph.back_office.models.Warehouse': 'ralph.back_office.tests.factories.WarehouseFactory', # noqa - 'ralph.dashboards.models.Dashboard': 'ralph.dashboards.tests.factories.DashboardFactory', # noqa - 'ralph.dashboards.models.Graph': 'ralph.dashboards.tests.factories.GraphFactory', # noqa - 'ralph.data_center.models.components.DiskShare': 'ralph.data_center.tests.factories.DiskShareFactory', # noqa - 'ralph.data_center.models.components.DiskShareMount': 'ralph.data_center.tests.factories.DiskShareMountFactory', # noqa - 'ralph.data_center.models.hosts.DCHost': 'ralph.data_center.tests.factories.DataCenterAssetFullFactory', # noqa - 'ralph.data_center.models.physical.Accessory': 'ralph.data_center.tests.factories.AccessoryFactory', # noqa - 'ralph.data_center.models.physical.DataCenter': 'ralph.data_center.tests.factories.DataCenterFactory', # noqa - 'ralph.data_center.models.physical.DataCenterAsset': 'ralph.data_center.tests.factories.DataCenterAssetFullFactory', # noqa - 'ralph.data_center.models.physical.Rack': 'ralph.data_center.tests.factories.RackFactory', # noqa - 'ralph.data_center.models.physical.RackAccessory': 'ralph.data_center.tests.factories.RackAccessoryFactory', # noqa - 'ralph.data_center.models.physical.ServerRoom': 'ralph.data_center.tests.factories.ServerRoomFactory', # noqa - 'ralph.data_center.models.virtual.BaseObjectCluster': 'ralph.data_center.tests.factories.BaseObjectClusterFactory', # noqa - 'ralph.data_center.models.virtual.Cluster': 'ralph.data_center.tests.factories.ClusterFactory', # noqa - 'ralph.data_center.models.virtual.ClusterType': 'ralph.data_center.tests.factories.ClusterTypeFactory', # noqa - 'ralph.data_center.models.virtual.Database': 'ralph.data_center.tests.factories.DatabaseFactory', # noqa - 'ralph.data_center.models.virtual.VIP': 'ralph.data_center.tests.factories.VIPFactory', # noqa - 'ralph.deployment.models.Preboot': 'ralph.deployment.tests.factories.PrebootFactory', # noqa - 'ralph.deployment.models.PrebootConfiguration': 'ralph.deployment.tests.factories.PrebootConfigurationFactory', # noqa - 'ralph.dhcp.models.DHCPServer': 'ralph.dhcp.tests.factories.DHCPServerFactory', # noqa - 'ralph.dhcp.models.DNSServer': 'ralph.dhcp.tests.factories.DNSServerFactory', # noqa - 'ralph.dhcp.models.DNSServerGroup': 'ralph.dhcp.tests.factories.DNSServerGroupFactory', # noqa - 'ralph.domains.models.domains.DNSProvider': 'ralph.domains.tests.factories.DNSProviderFactory', # noqa - 'ralph.domains.models.domains.Domain': 'ralph.domains.tests.factories.DomainFactory', # noqa - 'ralph.domains.models.domains.DomainCategory': 'ralph.domains.tests.factories.DomainCategoryFactory', # noqa - 'ralph.domains.models.domains.DomainContract': 'ralph.domains.tests.factories.DomainContractFactory', # noqa - 'ralph.domains.models.domains.DomainRegistrant': 'ralph.domains.tests.factories.DomainRegistrantFactory', # noqa - 'ralph.domains.models.domains.DomainProviderAdditionalServices': 'ralph.domains.tests.factories.DomainProviderAdditionalServicesFactory', # noqa - 'ralph.lib.custom_fields.models.CustomField': 'ralph.lib.custom_fields.tests.factories.CustomFieldFactory', # noqa - 'ralph.lib.transitions.models.Transition': 'ralph.lib.transitions.tests.factories.TransitionFactory', # noqa - 'ralph.lib.transitions.models.TransitionJob': 'ralph.lib.transitions.tests.factories.TransitionJobFactory', # noqa - 'ralph.lib.transitions.models.TransitionModel': 'ralph.lib.transitions.tests.factories.TransitionModelFactory', # noqa - 'ralph.lib.transitions.models.TransitionsHistory': 'ralph.lib.transitions.tests.factories.TransitionsHistoryFactory', # noqa - 'ralph.licences.models.Licence': 'ralph.licences.tests.factories.LicenceFactory', # noqa - 'ralph.licences.models.LicenceType': 'ralph.licences.tests.factories.LicenceTypeFactory', # noqa - 'ralph.licences.models.LicenceUser': 'ralph.licences.tests.factories.LicenceUserFactory', # noqa - 'ralph.licences.models.Software': 'ralph.licences.tests.factories.SoftwareFactory', # noqa - 'ralph.networks.models.networks.IPAddress': 'ralph.networks.tests.factories.IPAddressFactory', # noqa - 'ralph.networks.models.networks.Network': 'ralph.networks.tests.factories.NetworkFactory', # noqa - 'ralph.networks.models.networks.NetworkEnvironment': 'ralph.networks.tests.factories.NetworkEnvironmentFactory', # noqa - 'ralph.networks.models.networks.NetworkKind': 'ralph.networks.tests.factories.NetworkKindFactory', # noqa - 'ralph.operations.models.Change': 'ralph.operations.tests.factories.ChangeFactory', # noqa - 'ralph.operations.models.Failure': 'ralph.operations.tests.factories.FailureFactory', # noqa - 'ralph.operations.models.Incident': 'ralph.operations.tests.factories.IncidentFactory', # noqa - 'ralph.operations.models.Operation': 'ralph.operations.tests.factories.OperationFactory', # noqa - 'ralph.operations.models.OperationType': 'ralph.operations.tests.factories.OperationTypeFactory', # noqa - 'ralph.operations.models.Problem': 'ralph.operations.tests.factories.ProblemFactory', # noqa - 'ralph.operations.models.OperationStatus': 'ralph.operations.tests.factories.OperationStatusFactory', # noqa - 'ralph.reports.models.Report': 'ralph.reports.factories.ReportFactory', - 'ralph.reports.models.ReportLanguage': 'ralph.reports.factories.ReportLanguageFactory', # noqa - 'ralph.ssl_certificates.models.SSLCertificate': 'ralph.ssl_certificates.tests.factories.SSLCertificatesFactory', # noqa - 'ralph.supports.models.BaseObjectsSupport': 'ralph.supports.tests.factories.BaseObjectsSupportFactory', # noqa - 'ralph.supports.models.Support': 'ralph.supports.tests.factories.SupportFactory', # noqa - 'ralph.supports.models.SupportType': 'ralph.supports.tests.factories.SupportTypeFactory', # noqa - 'ralph.trade_marks.models.TradeMark': 'ralph.trade_marks.tests.factories.TradeMarkFactory', #noqa - 'ralph.trade_marks.models.TradeMarksLinkedDomains': 'ralph.trade_marks.tests.factories.TradeMarksLinkedDomainsFactory', # noqa - 'ralph.trade_marks.models.UtilityModel': 'ralph.trade_marks.tests.factories.UtilityModelFactory',# noqa - 'ralph.trade_marks.models.UtilityModelLinkedDomains': 'ralph.trade_marks.tests.factories.UtilityModelLinkedDomainsFactory',# noqa - 'ralph.trade_marks.models.ProviderAdditionalMarking': 'ralph.trade_marks.tests.factories.ProviderAdditionalMarkingFactory', # noqa - 'ralph.trade_marks.models.TradeMarkCountry': 'ralph.trade_marks.tests.factories.TradeMarkCountryFactory', # noqa - 'ralph.trade_marks.models.TradeMarkRegistrarInstitution': 'ralph.trade_marks.tests.factories.TradeMarkRegistrarInstitutionFactory', # noqa - 'ralph.virtual.models.CloudFlavor': 'ralph.virtual.tests.factories.CloudFlavorFactory', # noqa - 'ralph.virtual.models.CloudHost': 'ralph.virtual.tests.factories.CloudHostFullFactory', # noqa - 'ralph.virtual.models.CloudImage': 'ralph.virtual.tests.factories.CloudImageFactory', # noqa - 'ralph.virtual.models.CloudProject': 'ralph.virtual.tests.factories.CloudProjectFactory', # noqa - 'ralph.virtual.models.CloudProvider': 'ralph.virtual.tests.factories.CloudProviderFactory', # noqa - 'ralph.virtual.models.VirtualServer': 'ralph.virtual.tests.factories.VirtualServerFullFactory', # noqa - 'ralph.virtual.models.VirtualServerType': 'ralph.virtual.tests.factories.VirtualServerTypeFactory', # noqa - 'ralph.security.models.Vulnerability': 'ralph.security.tests.factories.VulnerabilityFactory', # noqa - 'ralph.security.models.SecurityScan': 'ralph.security.tests.factories.SecurityScanFactory', # noqa - 'ralph.sim_cards.models.SIMCard': 'ralph.sim_cards.tests.factories.SIMCardFactory', # noqa - 'ralph.sim_cards.models.CellularCarrier': 'ralph.sim_cards.tests.factories.CellularCarrierFactory', # noqa - 'ralph.sim_cards.models.SIMCardFeatures': 'ralph.sim_cards.tests.factories.SIMCardFeatureFactory', # noqa - 'ralph.trade_marks.models.Design': 'ralph.trade_marks.tests.factories.DesignFactory', # noqa - 'ralph.trade_marks.models.Patent': 'ralph.trade_marks.tests.factories.PatentFactory' # noqa - + "django.contrib.auth.models.Group": "ralph.accounts.tests.factories.GroupFactory", # noqa + "ralph.accessories.models.Accessory": "ralph.accessories.tests.factories.AccessoryFactory", # noqa + "ralph.access_cards.models.AccessCard": "ralph.access_cards.tests.factories.AccessCardFactory", # noqa + "ralph.access_cards.models.AccessZone": "ralph.access_cards.tests.factories.AccessZoneFactory", # noqa + "ralph.accounts.models.RalphUser": "ralph.accounts.tests.factories.UserFactory", # noqa + "ralph.accounts.models.Region": "ralph.accounts.tests.factories.RegionFactory", # noqa + "ralph.accounts.models.Team": "ralph.accounts.tests.factories.TeamFactory", + "ralph.assets.models.assets.AssetHolder": "ralph.assets.tests.factories.AssetHolderFactory", # noqa + "ralph.assets.models.assets.AssetModel": "ralph.assets.tests.factories.BackOfficeAssetModelFactory", # noqa + "ralph.assets.models.assets.BudgetInfo": "ralph.assets.tests.factories.BudgetInfoFactory", # noqa + "ralph.assets.models.assets.BusinessSegment": "ralph.assets.tests.factories.BusinessSegmentFactory", # noqa + "ralph.assets.models.assets.Category": "ralph.assets.tests.factories.CategoryFactory", # noqa + "ralph.assets.models.assets.Environment": "ralph.assets.tests.factories.EnvironmentFactory", # noqa + "ralph.assets.models.assets.Manufacturer": "ralph.assets.tests.factories.ManufacturerFactory", # noqa + "ralph.assets.models.assets.ManufacturerKind": "ralph.assets.tests.factories.ManufacturerKindFactory", # noqa + "ralph.assets.models.assets.ProfitCenter": "ralph.assets.tests.factories.ProfitCenterFactory", # noqa + "ralph.assets.models.assets.Service": "ralph.assets.tests.factories.ServiceFactory", # noqa + "ralph.assets.models.assets.ServiceEnvironment": "ralph.assets.tests.factories.ServiceEnvironmentFactory", # noqa + "ralph.assets.models.base.BaseObject": "ralph.assets.tests.factories.BaseObjectFactory", # noqa + "ralph.assets.models.components.ComponentModel": "ralph.assets.tests.factories.ComponentModelFactory", # noqa + "ralph.assets.models.components.Disk": "ralph.assets.tests.factories.DiskFactory", # noqa + "ralph.assets.models.components.Ethernet": "ralph.assets.tests.factories.EthernetFactory", # noqa + "ralph.assets.models.components.FibreChannelCard": "ralph.assets.tests.factories.FibreChannelCardFactory", # noqa + "ralph.assets.models.components.Memory": "ralph.assets.tests.factories.MemoryFactory", # noqa + "ralph.assets.models.components.Processor": "ralph.assets.tests.factories.ProcessorFactory", # noqa + "ralph.assets.models.configuration.ConfigurationClass": "ralph.assets.tests.factories.ConfigurationClassFactory", # noqa + "ralph.assets.models.configuration.ConfigurationModule": "ralph.assets.tests.factories.ConfigurationModuleFactory", # noqa + "ralph.back_office.models.BackOfficeAsset": "ralph.back_office.tests.factories.BackOfficeAssetFactory", # noqa + "ralph.back_office.models.OfficeInfrastructure": "ralph.back_office.tests.factories.OfficeInfrastructureFactory", # noqa + "ralph.back_office.models.Warehouse": "ralph.back_office.tests.factories.WarehouseFactory", # noqa + "ralph.dashboards.models.Dashboard": "ralph.dashboards.tests.factories.DashboardFactory", # noqa + "ralph.dashboards.models.Graph": "ralph.dashboards.tests.factories.GraphFactory", # noqa + "ralph.data_center.models.components.DiskShare": "ralph.data_center.tests.factories.DiskShareFactory", # noqa + "ralph.data_center.models.components.DiskShareMount": "ralph.data_center.tests.factories.DiskShareMountFactory", # noqa + "ralph.data_center.models.hosts.DCHost": "ralph.data_center.tests.factories.DataCenterAssetFullFactory", # noqa + "ralph.data_center.models.physical.Accessory": "ralph.data_center.tests.factories.AccessoryFactory", # noqa + "ralph.data_center.models.physical.DataCenter": "ralph.data_center.tests.factories.DataCenterFactory", # noqa + "ralph.data_center.models.physical.DataCenterAsset": "ralph.data_center.tests.factories.DataCenterAssetFullFactory", # noqa + "ralph.data_center.models.physical.Rack": "ralph.data_center.tests.factories.RackFactory", # noqa + "ralph.data_center.models.physical.RackAccessory": "ralph.data_center.tests.factories.RackAccessoryFactory", # noqa + "ralph.data_center.models.physical.ServerRoom": "ralph.data_center.tests.factories.ServerRoomFactory", # noqa + "ralph.data_center.models.virtual.BaseObjectCluster": "ralph.data_center.tests.factories.BaseObjectClusterFactory", # noqa + "ralph.data_center.models.virtual.Cluster": "ralph.data_center.tests.factories.ClusterFactory", # noqa + "ralph.data_center.models.virtual.ClusterType": "ralph.data_center.tests.factories.ClusterTypeFactory", # noqa + "ralph.data_center.models.virtual.Database": "ralph.data_center.tests.factories.DatabaseFactory", # noqa + "ralph.data_center.models.virtual.VIP": "ralph.data_center.tests.factories.VIPFactory", # noqa + "ralph.deployment.models.Preboot": "ralph.deployment.tests.factories.PrebootFactory", # noqa + "ralph.deployment.models.PrebootConfiguration": "ralph.deployment.tests.factories.PrebootConfigurationFactory", # noqa + "ralph.dhcp.models.DHCPServer": "ralph.dhcp.tests.factories.DHCPServerFactory", # noqa + "ralph.dhcp.models.DNSServer": "ralph.dhcp.tests.factories.DNSServerFactory", # noqa + "ralph.dhcp.models.DNSServerGroup": "ralph.dhcp.tests.factories.DNSServerGroupFactory", # noqa + "ralph.domains.models.domains.DNSProvider": "ralph.domains.tests.factories.DNSProviderFactory", # noqa + "ralph.domains.models.domains.Domain": "ralph.domains.tests.factories.DomainFactory", # noqa + "ralph.domains.models.domains.DomainCategory": "ralph.domains.tests.factories.DomainCategoryFactory", # noqa + "ralph.domains.models.domains.DomainContract": "ralph.domains.tests.factories.DomainContractFactory", # noqa + "ralph.domains.models.domains.DomainRegistrant": "ralph.domains.tests.factories.DomainRegistrantFactory", # noqa + "ralph.domains.models.domains.DomainProviderAdditionalServices": "ralph.domains.tests.factories.DomainProviderAdditionalServicesFactory", # noqa + "ralph.lib.custom_fields.models.CustomField": "ralph.lib.custom_fields.tests.factories.CustomFieldFactory", # noqa + "ralph.lib.transitions.models.Transition": "ralph.lib.transitions.tests.factories.TransitionFactory", # noqa + "ralph.lib.transitions.models.TransitionJob": "ralph.lib.transitions.tests.factories.TransitionJobFactory", # noqa + "ralph.lib.transitions.models.TransitionModel": "ralph.lib.transitions.tests.factories.TransitionModelFactory", # noqa + "ralph.lib.transitions.models.TransitionsHistory": "ralph.lib.transitions.tests.factories.TransitionsHistoryFactory", # noqa + "ralph.licences.models.Licence": "ralph.licences.tests.factories.LicenceFactory", # noqa + "ralph.licences.models.LicenceType": "ralph.licences.tests.factories.LicenceTypeFactory", # noqa + "ralph.licences.models.LicenceUser": "ralph.licences.tests.factories.LicenceUserFactory", # noqa + "ralph.licences.models.Software": "ralph.licences.tests.factories.SoftwareFactory", # noqa + "ralph.networks.models.networks.IPAddress": "ralph.networks.tests.factories.IPAddressFactory", # noqa + "ralph.networks.models.networks.Network": "ralph.networks.tests.factories.NetworkFactory", # noqa + "ralph.networks.models.networks.NetworkEnvironment": "ralph.networks.tests.factories.NetworkEnvironmentFactory", # noqa + "ralph.networks.models.networks.NetworkKind": "ralph.networks.tests.factories.NetworkKindFactory", # noqa + "ralph.operations.models.Change": "ralph.operations.tests.factories.ChangeFactory", # noqa + "ralph.operations.models.Failure": "ralph.operations.tests.factories.FailureFactory", # noqa + "ralph.operations.models.Incident": "ralph.operations.tests.factories.IncidentFactory", # noqa + "ralph.operations.models.Operation": "ralph.operations.tests.factories.OperationFactory", # noqa + "ralph.operations.models.OperationType": "ralph.operations.tests.factories.OperationTypeFactory", # noqa + "ralph.operations.models.Problem": "ralph.operations.tests.factories.ProblemFactory", # noqa + "ralph.operations.models.OperationStatus": "ralph.operations.tests.factories.OperationStatusFactory", # noqa + "ralph.reports.models.Report": "ralph.reports.factories.ReportFactory", + "ralph.reports.models.ReportLanguage": "ralph.reports.factories.ReportLanguageFactory", # noqa + "ralph.ssl_certificates.models.SSLCertificate": "ralph.ssl_certificates.tests.factories.SSLCertificatesFactory", # noqa + "ralph.supports.models.BaseObjectsSupport": "ralph.supports.tests.factories.BaseObjectsSupportFactory", # noqa + "ralph.supports.models.Support": "ralph.supports.tests.factories.SupportFactory", # noqa + "ralph.supports.models.SupportType": "ralph.supports.tests.factories.SupportTypeFactory", # noqa + "ralph.trade_marks.models.TradeMark": "ralph.trade_marks.tests.factories.TradeMarkFactory", # noqa + "ralph.trade_marks.models.TradeMarksLinkedDomains": "ralph.trade_marks.tests.factories.TradeMarksLinkedDomainsFactory", # noqa + "ralph.trade_marks.models.UtilityModel": "ralph.trade_marks.tests.factories.UtilityModelFactory", # noqa + "ralph.trade_marks.models.UtilityModelLinkedDomains": "ralph.trade_marks.tests.factories.UtilityModelLinkedDomainsFactory", # noqa + "ralph.trade_marks.models.ProviderAdditionalMarking": "ralph.trade_marks.tests.factories.ProviderAdditionalMarkingFactory", # noqa + "ralph.trade_marks.models.TradeMarkCountry": "ralph.trade_marks.tests.factories.TradeMarkCountryFactory", # noqa + "ralph.trade_marks.models.TradeMarkRegistrarInstitution": "ralph.trade_marks.tests.factories.TradeMarkRegistrarInstitutionFactory", # noqa + "ralph.virtual.models.CloudFlavor": "ralph.virtual.tests.factories.CloudFlavorFactory", # noqa + "ralph.virtual.models.CloudHost": "ralph.virtual.tests.factories.CloudHostFullFactory", # noqa + "ralph.virtual.models.CloudImage": "ralph.virtual.tests.factories.CloudImageFactory", # noqa + "ralph.virtual.models.CloudProject": "ralph.virtual.tests.factories.CloudProjectFactory", # noqa + "ralph.virtual.models.CloudProvider": "ralph.virtual.tests.factories.CloudProviderFactory", # noqa + "ralph.virtual.models.VirtualServer": "ralph.virtual.tests.factories.VirtualServerFullFactory", # noqa + "ralph.virtual.models.VirtualServerType": "ralph.virtual.tests.factories.VirtualServerTypeFactory", # noqa + "ralph.security.models.Vulnerability": "ralph.security.tests.factories.VulnerabilityFactory", # noqa + "ralph.security.models.SecurityScan": "ralph.security.tests.factories.SecurityScanFactory", # noqa + "ralph.sim_cards.models.SIMCard": "ralph.sim_cards.tests.factories.SIMCardFactory", # noqa + "ralph.sim_cards.models.CellularCarrier": "ralph.sim_cards.tests.factories.CellularCarrierFactory", # noqa + "ralph.sim_cards.models.SIMCardFeatures": "ralph.sim_cards.tests.factories.SIMCardFeatureFactory", # noqa + "ralph.trade_marks.models.Design": "ralph.trade_marks.tests.factories.DesignFactory", # noqa + "ralph.trade_marks.models.Patent": "ralph.trade_marks.tests.factories.PatentFactory", # noqa } EXCLUDE_MODELS = [ - 'django.contrib.contenttypes.models.ContentType', - 'ralph.assets.models.assets.Asset', - 'ralph.assets.models.base.BaseObject', # TODO: Add in the future - 'ralph.assets.models.components.GenericComponent', - 'ralph.data_center.models.physical.Connection', - 'ralph.deployment.models.Deployment', - 'ralph.deployment.models.PrebootFile', - 'ralph.deployment.models.PrebootItem', - 'ralph.lib.custom_fields.models.CustomField', - 'ralph.lib.transitions.models.TransitionModel', - 'ralph.networks.models.networks.DiscoveryQueue', - 'ralph.tests.models.Bar', - 'ralph.tests.models.Car', - 'ralph.tests.models.Car2', - 'ralph.tests.models.Foo', - 'ralph.tests.models.TestManufacturer', - 'ralph.tests.models.Order', - 'ralph.tests.models.PolymorphicTestModel', + "django.contrib.contenttypes.models.ContentType", + "ralph.assets.models.assets.Asset", + "ralph.assets.models.base.BaseObject", # TODO: Add in the future + "ralph.assets.models.components.GenericComponent", + "ralph.data_center.models.physical.Connection", + "ralph.deployment.models.Deployment", + "ralph.deployment.models.PrebootFile", + "ralph.deployment.models.PrebootItem", + "ralph.lib.custom_fields.models.CustomField", + "ralph.lib.transitions.models.TransitionModel", + "ralph.networks.models.networks.DiscoveryQueue", + "ralph.tests.models.Bar", + "ralph.tests.models.Car", + "ralph.tests.models.Car2", + "ralph.tests.models.Foo", + "ralph.tests.models.TestManufacturer", + "ralph.tests.models.Order", + "ralph.tests.models.PolymorphicTestModel", ] EXCLUDE_ADD_VIEW = [ - 'ralph.assets.models.base.BaseObject', - 'ralph.data_center.models.hosts.DCHost', - 'ralph.supports.models.BaseObjectsSupport', + "ralph.assets.models.base.BaseObject", + "ralph.data_center.models.hosts.DCHost", + "ralph.supports.models.BaseObjectsSupport", ] SQL_QUERY_LIMIT = 30 @@ -153,9 +152,9 @@ @ddt class ViewsTest(TestCase): def setUp(self): - self.request = RequestFactory().get('/') + self.request = RequestFactory().get("/") self.request.user = get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' + "test", "test@test.test", "test" ) self.request.session = {} @@ -163,81 +162,72 @@ def setUp(self): ContentType.objects.get_for_models(*ralph_site._registry.keys()) @data(*ralph_site._registry.keys()) - def test_numbers_of_sql_query_and_response_status_is_200( - self, model - ): - model_admin = ralph_site._registry[model] - query_count = 0 - model_class_path = '{}.{}'.format(model.__module__, model.__name__) - if model_class_path in EXCLUDE_MODELS: - return - - module_path, factory_class = FACTORY_MAP[model_class_path].rsplit( - '.', 1 - ) - module = import_module(module_path) - factory_model = getattr(module, factory_class) - - # Create 10 records: - factory_model.create_batch(10) - - with CaptureQueriesContext(connections['default']) as cqc: - change_list = model_admin.changelist_view(self.request) - self.assertEqual(change_list.status_code, 200) - query_count = len(cqc) - - # Create next 10 records: - factory_model.create_batch(10) - - with CaptureQueriesContext(connections['default']) as cqc2: - change_list = model_admin.changelist_view(self.request) - self.assertEqual( - query_count, - len(cqc2), - 'Different query count for {}: \n {} \nvs\n{}'.format( - model_class_path, - '\n'.join([q['sql'] for q in cqc.captured_queries]), - '\n'.join([q['sql'] for q in cqc2.captured_queries]), - ) - ) - self.assertFalse(len(cqc2) > SQL_QUERY_LIMIT) - - if model_class_path not in EXCLUDE_ADD_VIEW: - change_form = model_admin.changeform_view( - self.request, object_id=None - ) - self.assertEqual(change_form.status_code, 200) - change_form = model_admin.changeform_view( - self.request, object_id=str(model.objects.first().id) + def test_numbers_of_sql_query_and_response_status_is_200(self, model): + model_admin = ralph_site._registry[model] + query_count = 0 + model_class_path = "{}.{}".format(model.__module__, model.__name__) + if model_class_path in EXCLUDE_MODELS: + return + + module_path, factory_class = FACTORY_MAP[model_class_path].rsplit(".", 1) + module = import_module(module_path) + factory_model = getattr(module, factory_class) + + # Create 10 records: + factory_model.create_batch(10) + + with CaptureQueriesContext(connections["default"]) as cqc: + change_list = model_admin.changelist_view(self.request) + self.assertEqual(change_list.status_code, 200) + query_count = len(cqc) + + # Create next 10 records: + factory_model.create_batch(10) + + with CaptureQueriesContext(connections["default"]) as cqc2: + change_list = model_admin.changelist_view(self.request) + self.assertEqual( + query_count, + len(cqc2), + "Different query count for {}: \n {} \nvs\n{}".format( + model_class_path, + "\n".join([q["sql"] for q in cqc.captured_queries]), + "\n".join([q["sql"] for q in cqc2.captured_queries]), + ), ) + self.assertFalse(len(cqc2) > SQL_QUERY_LIMIT) + + if model_class_path not in EXCLUDE_ADD_VIEW: + change_form = model_admin.changeform_view(self.request, object_id=None) self.assertEqual(change_form.status_code, 200) + change_form = model_admin.changeform_view( + self.request, object_id=str(model.objects.first().id) + ) + self.assertEqual(change_form.status_code, 200) class ViewMixinTest(TestCase): def setUp(self): - password = 'secret' + password = "secret" self.user = get_user_model().objects.create_superuser( - 'test', 'test@test.test', password - ) - self.client.login( - username=self.user.username, - password=password + "test", "test@test.test", password ) + self.client.login(username=self.user.username, password=password) def test_redirect_when_one_result_after_searching(self): model = Foo - obj = model.objects.create(bar='test1') + obj = model.objects.create(bar="test1") info = model._meta.app_label, model._meta.model_name - url = reverse('admin:{}_{}_changelist'.format(*info)) - url += '?bar={}'.format(obj.bar) + url = reverse("admin:{}_{}_changelist".format(*info)) + url += "?bar={}".format(obj.bar) response = self.client.get(url) self.assertEqual(response.status_code, 302) self.assertTrue(response.url.endswith(obj.get_absolute_url())) def test_do_not_redirect_when_is_not_filtering(self): model = Foo - model.objects.create(bar='test#1') + model.objects.create(bar="test#1") info = model._meta.app_label, model._meta.model_name - url = reverse('admin:{}_{}_changelist'.format(*info)) + url = reverse("admin:{}_{}_changelist".format(*info)) response = self.client.get(url) self.assertEqual(response.status_code, 200) diff --git a/src/ralph/admin/tests/tests_widgets.py b/src/ralph/admin/tests/tests_widgets.py index 35b052faf9..8d8f1a0ac8 100644 --- a/src/ralph/admin/tests/tests_widgets.py +++ b/src/ralph/admin/tests/tests_widgets.py @@ -7,29 +7,29 @@ class PerimissionsSelectWidgetTest(SimpleTestCase): def setUp(self): super().setUp() - self.separator = ' | ' + self.separator = " | " self.choices = ( - (1, self.separator.join(['app', 'model', 'can view model'])), - (2, self.separator.join(['app', 'model', 'can change model'])), - (3, self.separator.join(['app', 'model', 'can delete model'])), + (1, self.separator.join(["app", "model", "can view model"])), + (2, self.separator.join(["app", "model", "can change model"])), + (3, self.separator.join(["app", "model", "can delete model"])), ) self.widget = PermissionsSelectWidget(choices=self.choices) def test_render(self): """Test render items.""" - rendered_widget = self.widget.render(name='test_perms', value='') + rendered_widget = self.widget.render(name="test_perms", value="") for value, label in self.choices: self.assertTrue(label.split(self.separator)[-1] in rendered_widget) def test_render_selected_option(self): """Test selected option.""" - rendered_option = self.widget.render_option([1, 2, 3], 1, 'test') - self.assertTrue('checked' in rendered_option) + rendered_option = self.widget.render_option([1, 2, 3], 1, "test") + self.assertTrue("checked" in rendered_option) def test_get_value_from_dict(self): """Test get value from dictionary.""" - name = 'test_perms' + name = "test_perms" value = self.widget.value_from_datadict( - data={name: '1,2,3'}, files=None, name=name + data={name: "1,2,3"}, files=None, name=name ) self.assertEqual(value, [1, 2, 3]) diff --git a/src/ralph/admin/views/extra.py b/src/ralph/admin/views/extra.py index 971a835bc6..950980c33c 100644 --- a/src/ralph/admin/views/extra.py +++ b/src/ralph/admin/views/extra.py @@ -9,13 +9,13 @@ get_inline_media, initialize_search_form, RalphAdmin, - RalphTemplateView + RalphTemplateView, ) from ralph.admin.sites import ralph_site from ralph.helpers import get_model_view_url_name from ralph.lib.permissions.views import PermissionViewMetaClass -VIEW_TYPES = CHANGE, LIST = ('change', 'list') +VIEW_TYPES = CHANGE, LIST = ("change", "list") class RalphExtraViewMixin(object): @@ -33,39 +33,39 @@ def dispatch(self, request, model, views, *args, **kwargs): @classmethod def post_register(cls, namespace, model): # make sure that single view is not processed more than once - if getattr(cls, 'namespace', None): - raise ImproperlyConfigured(( - 'Single view class ({}) cannot be attached to more than one ' - 'admin site' - ).format(cls.__name__)) + if getattr(cls, "namespace", None): + raise ImproperlyConfigured( + ( + "Single view class ({}) cannot be attached to more than one " + "admin site" + ).format(cls.__name__) + ) cls.namespace = namespace - cls.url_to_reverse = '{}_{}_{}'.format( + cls.url_to_reverse = "{}_{}_{}".format( model._meta.app_label, model._meta.model_name, cls.url_name ) - cls.url_with_namespace = ':'.join([ - cls.namespace, cls.url_to_reverse - ]) + cls.url_with_namespace = ":".join([cls.namespace, cls.url_to_reverse]) def get_name(self): if not self.name: raise NotImplementedError( - 'Please define name for {}'.format(self.__class__) + "Please define name for {}".format(self.__class__) ) return self.name def get_extra_view_base_template(self): if not self.extra_view_base_template: raise NotImplementedError( - 'Please define base template for {}'.format(self.__class__) + "Please define base template for {}".format(self.__class__) ) return self.extra_view_base_template def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update(ralph_site.each_context(self.request)) - context['BASE_TEMPLATE'] = self.get_extra_view_base_template() - context['title'] = self.label - context['view_name'] = self.name + context["BASE_TEMPLATE"] = self.get_extra_view_base_template() + context["title"] = self.label + context["view_name"] = self.name return context def get_template_names(self): @@ -74,67 +74,60 @@ def get_template_names(self): model = self.model._meta.model_name if self.template_name: templates = [self.template_name] - templates.extend([ - '{}/{}.html'.format(model, self.get_name()), - '{}/{}/{}.html'.format(app_label, model, self.get_name()) - ]) + templates.extend( + [ + "{}/{}.html".format(model, self.get_name()), + "{}/{}/{}.html".format(app_label, model, self.get_name()), + ] + ) return templates class RalphListView(RalphExtraViewMixin, RalphTemplateView): _type = LIST - extra_view_base_template = 'admin/extra_views/base_list.html' + extra_view_base_template = "admin/extra_views/base_list.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['change_views'] = self.views + context["change_views"] = self.views return context @classmethod def get_url_pattern(cls, model): - return r'^{}/{}/{}/$'.format( + return r"^{}/{}/{}/$".format( model._meta.app_label, model._meta.model_name, cls.url_name ) class AdminViewBase(type): def __new__(cls, name, bases, attrs): - base_template = 'admin/extra_views/base_admin_change.html' - empty_fieldset = (('__empty__', {'fields': []}),) + base_template = "admin/extra_views/base_admin_change.html" + empty_fieldset = (("__empty__", {"fields": []}),) new_class = super().__new__(cls, name, bases, attrs) - admin_whitelist = ['inlines', 'fieldsets', 'readonly_fields'] - if hasattr(new_class, 'admin_attribute_list_to_copy'): + admin_whitelist = ["inlines", "fieldsets", "readonly_fields"] + if hasattr(new_class, "admin_attribute_list_to_copy"): admin_whitelist.extend(new_class.admin_attribute_list_to_copy) - admin_attrs = { - key: attrs.pop(key, []) for key in admin_whitelist - } + admin_attrs = {key: attrs.pop(key, []) for key in admin_whitelist} # create admin class - admin_attrs['change_form_template'] = base_template + admin_attrs["change_form_template"] = base_template # rewrite admin fields from bases for base in bases: - base_admin_class = getattr(base, 'admin_class', None) - if ( - not base_admin_class or - not issubclass(base_admin_class, RalphAdmin) - ): + base_admin_class = getattr(base, "admin_class", None) + if not base_admin_class or not issubclass(base_admin_class, RalphAdmin): continue - for field in admin_whitelist + ['change_form_template']: - admin_attrs[field] = ( - admin_attrs[field] or getattr( - base_admin_class, field, None - ) + for field in admin_whitelist + ["change_form_template"]: + admin_attrs[field] = admin_attrs[field] or getattr( + base_admin_class, field, None ) - admin_attrs['fieldsets'] = admin_attrs['fieldsets'] or empty_fieldset - new_class.admin_class = type('AdminView', (RalphAdmin,), admin_attrs) + admin_attrs["fieldsets"] = admin_attrs["fieldsets"] or empty_fieldset + new_class.admin_class = type("AdminView", (RalphAdmin,), admin_attrs) return new_class PermissionAdminViewBase = type( - 'PermissionAdminViewBase', - (PermissionViewMetaClass, AdminViewBase), - {} + "PermissionAdminViewBase", (PermissionViewMetaClass, AdminViewBase), {} ) @@ -142,7 +135,7 @@ class RalphDetailView( RalphExtraViewMixin, RalphTemplateView, metaclass=PermissionAdminViewBase ): _type = CHANGE - extra_view_base_template = 'admin/extra_views/base_change.html' + extra_view_base_template = "admin/extra_views/base_change.html" summary_fields = None def get_object(self, model, pk): @@ -157,36 +150,35 @@ def dispatch(self, request, model, pk, *args, **kwargs): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['object'] = context['original'] = self.object - context['change_views'] = self.views - context['media'] = get_inline_media() - context['summary_fields'] = self.summary_fields or [] + context["object"] = context["original"] = self.object + context["change_views"] = self.views + context["media"] = get_inline_media() + context["summary_fields"] = self.summary_fields or [] initialize_search_form(self.object.__class__, context) return context @classmethod def get_url_pattern(cls, model): - return r'^{}/{}/(?P[0-9]+)/{}/$'.format( + return r"^{}/{}/(?P[0-9]+)/{}/$".format( model._meta.app_label, model._meta.model_name, cls.url_name ) class RalphDetailViewAdmin(RalphDetailView): """This class helps to display standard model admin in tab.""" + def dispatch(self, request, model, pk, *args, **kwargs): self.object = get_object_or_404(model, pk=pk) - self.views = kwargs['views'] + self.views = kwargs["views"] extra_context = copy(super().get_context_data()) - extra_context['object'] = self.object - extra_context['transition_url_name'] = get_model_view_url_name( - model, 'transition' + extra_context["object"] = self.object + extra_context["transition_url_name"] = get_model_view_url_name( + model, "transition" ) self.admin_class_instance = self.admin_class( model, ralph_site, change_views=self.views ) - extra_context['media'] += self.admin_class_instance.media + extra_context["media"] += self.admin_class_instance.media return self.admin_class_instance.change_view( - request, - pk, - extra_context=extra_context + request, pk, extra_context=extra_context ) diff --git a/src/ralph/admin/views/main.py b/src/ralph/admin/views/main.py index 6a02fcb429..5ed30c923e 100644 --- a/src/ralph/admin/views/main.py +++ b/src/ralph/admin/views/main.py @@ -1,14 +1,13 @@ # -*- coding: utf-8 -*- from django.contrib.admin.views.main import ChangeList, SEARCH_VAR -SEARCH_SCOPE_VAR = 'search-scope' -BULK_EDIT_VAR = 'bulk_edit' -BULK_EDIT_VAR_IDS = 'id' +SEARCH_SCOPE_VAR = "search-scope" +BULK_EDIT_VAR = "bulk_edit" +BULK_EDIT_VAR_IDS = "id" IGNORED_FIELDS = (BULK_EDIT_VAR, BULK_EDIT_VAR_IDS, SEARCH_SCOPE_VAR) class RalphChangeList(ChangeList): - def __init__(self, request, *args, **kwargs): self.bulk_edit = request.GET.get(BULK_EDIT_VAR, False) super().__init__(request, *args, **kwargs) @@ -18,7 +17,7 @@ def get_filters_params(self, params=None): for field in IGNORED_FIELDS: if field in result: del result[field] - return {key: value for key, value in result.items() if value != ''} + return {key: value for key, value in result.items() if value != ""} @property def any_filters(self): @@ -40,7 +39,7 @@ def get_ordering_from_related_model_admin(self, prefix, field_name): else: if all([model_admin, model_admin.ordering]): fields = [ - '{}{}__{}'.format(prefix, field_name, order.lstrip('-')) + "{}{}__{}".format(prefix, field_name, order.lstrip("-")) for order in model_admin.ordering ] return fields @@ -52,10 +51,8 @@ def get_ordering(self, request, queryset): old_ordering = super().get_ordering(request, queryset) ordering = [] for field_order in old_ordering: - _, prefix, field = field_order.rpartition('-') - ordering.extend( - self.get_ordering_from_related_model_admin(prefix, field) - ) + _, prefix, field = field_order.rpartition("-") + ordering.extend(self.get_ordering_from_related_model_admin(prefix, field)) return ordering def get_queryset(self, request): @@ -64,21 +61,15 @@ def get_queryset(self, request): # For popup window we limit display of records to the same as # we have in the autocomplete widget. autocomplete_queryset = getattr( - self.model, 'get_autocomplete_queryset', None + self.model, "get_autocomplete_queryset", None ) if autocomplete_queryset: autocomplete_queryset = autocomplete_queryset() # #2248 - cannot combine unique (distinct) and non-unique query # if one of the queries is distinct, make sure all are distinct - if ( - queryset.query.distinct and - not autocomplete_queryset.query.distinct - ): + if queryset.query.distinct and not autocomplete_queryset.query.distinct: autocomplete_queryset = autocomplete_queryset.distinct() - if ( - not queryset.query.distinct and - autocomplete_queryset.query.distinct - ): + if not queryset.query.distinct and autocomplete_queryset.query.distinct: queryset = queryset.distinct() queryset = queryset & autocomplete_queryset return queryset diff --git a/src/ralph/admin/views/multiadd.py b/src/ralph/admin/views/multiadd.py index ec80d9d5bf..8fd5a0c30e 100644 --- a/src/ralph/admin/views/multiadd.py +++ b/src/ralph/admin/views/multiadd.py @@ -13,7 +13,7 @@ from ralph.admin.fields import ( IntegerMultilineField, MultilineField, - MultivalueFormMixin + MultivalueFormMixin, ) from ralph.admin.mixins import RalphTemplateView from ralph.admin.sites import ralph_site @@ -21,17 +21,16 @@ class MultiAddView(RalphTemplateView): - """Adding view to multiple adds models.""" - template_name = 'admin/multi_add.html' + template_name = "admin/multi_add.html" def dispatch(self, request, object_pk, model, *args, **kwargs): admin_model = ralph_site._registry[model] self.model = model - if not request.user.has_perm('{}.add_{}'.format( - self.model._meta.app_label, self.model._meta.model_name - )): + if not request.user.has_perm( + "{}.add_{}".format(self.model._meta.app_label, self.model._meta.model_name) + ): return HttpResponseForbidden() self.info_fields = admin_model.multiadd_info_fields self.obj = get_object_or_404(model, pk=object_pk) @@ -43,36 +42,36 @@ def dispatch(self, request, object_pk, model, *args, **kwargs): def get_form(self): form_kwargs = {} multi_form_attrs = { - 'multivalue_fields': [i['field'] for i in self.fields], - 'model': self.model, - 'one_of_mulitvalue_required': self.one_of_mulitval_required, + "multivalue_fields": [i["field"] for i in self.fields], + "model": self.model, + "one_of_mulitvalue_required": self.one_of_mulitval_required, } for item in self.fields: - field_type = self.model._meta.get_field(item['field']) - required = item.get('required', not field_type.blank) + field_type = self.model._meta.get_field(item["field"]) + required = item.get("required", not field_type.blank) if isinstance(field_type, models.IntegerField): - multi_form_attrs[item['field']] = IntegerMultilineField( - allow_duplicates=item['allow_duplicates'], + multi_form_attrs[item["field"]] = IntegerMultilineField( + allow_duplicates=item["allow_duplicates"], required=required, ) else: - multi_form_attrs[item['field']] = MultilineField( - allow_duplicates=item['allow_duplicates'], + multi_form_attrs[item["field"]] = MultilineField( + allow_duplicates=item["allow_duplicates"], required=required, ) multi_form = type( - 'MultiForm', (MultivalueFormMixin, forms.Form), multi_form_attrs + "MultiForm", (MultivalueFormMixin, forms.Form), multi_form_attrs ) - if self.request.method == 'POST': - form_kwargs['data'] = self.request.POST + if self.request.method == "POST": + form_kwargs["data"] = self.request.POST return multi_form(**form_kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['form'] = self.get_form() - context['obj'] = self.obj - context['info_fields'] = self.info_fields + context["form"] = self.get_form() + context["obj"] = self.obj + context["info_fields"] = self.info_fields return context def post(self, request, *args, **kwargs): @@ -82,7 +81,7 @@ def post(self, request, *args, **kwargs): return self.form_valid(form) except IntegrityError as e: context = self.get_context_data() - context['form'] = form + context["form"] = form form.add_error(None, e.args[1]) return self.render_to_response(context) else: @@ -90,7 +89,7 @@ def post(self, request, *args, **kwargs): def form_invalid(self, form): context = self.get_context_data() - context['form'] = form + context["form"] = form return self.render_to_response(context) def get_url_name(self): @@ -98,7 +97,7 @@ def get_url_name(self): Return URl for model change list. """ params = self.model._meta.app_label, self.model._meta.model_name - url = 'admin:{}_{}_changelist'.format(*params) + url = "admin:{}_{}_changelist".format(*params) return reverse(url) def _get_ancestors_pointers(self, model): @@ -111,17 +110,17 @@ def _get_ancestors_pointers(self, model): @transaction.atomic def form_valid(self, form): saved_objects = [] - args = [form.cleaned_data[field['field']] for field in self.fields] + args = [form.cleaned_data[field["field"]] for field in self.fields] for data in zip(*args): for field in self._get_ancestors_pointers(self.obj): setattr(self.obj, field, None) self.obj.id = self.obj.pk = None for field in self.clear_fields: - setattr(self.obj, field['field'], field['value']) + setattr(self.obj, field["field"], field["value"]) for i, field in enumerate(self.fields): - setattr(self.obj, field['field'], data[i]) + setattr(self.obj, field["field"], data[i]) try: self.obj.clean() @@ -131,25 +130,21 @@ def form_valid(self, form): return self.form_invalid(form) self.obj.save() - saved_objects.append('{}'.format( - self.obj.get_absolute_url(), - str(self.obj) - )) + saved_objects.append( + '{}'.format(self.obj.get_absolute_url(), str(self.obj)) + ) messages.success( self.request, mark_safe( - _('Saved %(count)d object(s): %(objects)s') % { - 'count': len(saved_objects), - 'objects': ", ".join(saved_objects) - } - ) + _("Saved %(count)d object(s): %(objects)s") + % {"count": len(saved_objects), "objects": ", ".join(saved_objects)} + ), ) return HttpResponseRedirect(self.get_url_name()) class MulitiAddAdminMixin(object): - """ Multi add admin mixin. @@ -179,36 +174,32 @@ def get_multiadd_clear_fields(self, obj=None): return self.multiadd_clear_fields def get_url_name(self, with_namespace=True): - return get_model_view_url_name(self.model, 'multiadd', with_namespace) + return get_model_view_url_name(self.model, "multiadd", with_namespace) - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, form_url="", extra_context=None): if not extra_context: extra_context = {} if self.has_add_permission(request): - extra_context.update({ - 'multi_add_field': True - }) + extra_context.update({"multi_add_field": True}) return super().add_view(request, form_url, extra_context) - def change_view(self, request, object_id, form_url='', extra_context=None): + def change_view(self, request, object_id, form_url="", extra_context=None): if not extra_context: extra_context = {} if self.has_add_permission(request): - extra_context.update({ - 'multi_add_url': reverse(self.get_url_name(), args=[object_id]) - }) + extra_context.update( + {"multi_add_url": reverse(self.get_url_name(), args=[object_id])} + ) - return super().change_view( - request, object_id, form_url, extra_context - ) + return super().change_view(request, object_id, form_url, extra_context) def get_urls(self): urls = super().get_urls() _urls = [ url( - r'^(?P.+)/multiadd/$', + r"^(?P.+)/multiadd/$", self.admin_site.admin_view(self.view.as_view()), - {'model': self.model}, + {"model": self.model}, name=self.get_url_name(False), ), ] @@ -220,8 +211,6 @@ def response_add(self, request, obj, post_url_continue=None): Adding support for multiadd. """ - if '_multi_add' in request.POST: - return HttpResponseRedirect( - reverse(self.get_url_name(), args=[obj.pk]) - ) + if "_multi_add" in request.POST: + return HttpResponseRedirect(reverse(self.get_url_name(), args=[obj.pk])) return super().response_add(request, obj, post_url_continue) diff --git a/src/ralph/admin/widgets.py b/src/ralph/admin/widgets.py index d906cc12dd..bdffa614b4 100644 --- a/src/ralph/admin/widgets.py +++ b/src/ralph/admin/widgets.py @@ -24,35 +24,36 @@ from ralph.admin.autocomplete import get_results from ralph.admin.helpers import get_field_by_relation_path -ReadOnlyWidget = forms.TextInput(attrs={'readonly': 'readonly'}) +ReadOnlyWidget = forms.TextInput(attrs={"readonly": "readonly"}) logger = logging.getLogger(__name__) class DatepickerWidgetMixin: - css_class = 'datepicker' + css_class = "datepicker" @property def media(self): - js = map(lambda x: os.path.join(*x), [ - ('vendor', 'js', 'foundation-datepicker.js'), - ('src', 'js', 'foundation-datepicker-init.js'), - ]) - return forms.Media(js=[ - static(path) for path in js - ]) + js = map( + lambda x: os.path.join(*x), + [ + ("vendor", "js", "foundation-datepicker.js"), + ("src", "js", "foundation-datepicker-init.js"), + ], + ) + return forms.Media(js=[static(path) for path in js]) def render(self, name, value, attrs=None, renderer=None): - attrs['class'] = self.css_class + attrs["class"] = self.css_class return super().render(name, value, attrs=attrs, renderer=renderer) class AdminDateWidget(DatepickerWidgetMixin, forms.DateInput): - css_class = 'datepicker' + css_class = "datepicker" class AdminDateTimeWidget(DatepickerWidgetMixin, forms.DateTimeInput): - css_class = 'datepicker-with-time' + css_class = "datepicker-with-time" class PermissionsSelectWidget(forms.Widget): @@ -62,28 +63,26 @@ def __init__(self, attrs=None, choices=()): @property def media(self): - js = ['multi.js'] - return forms.Media(js=[ - static(os.path.join('src', 'js', path)) for path in js - ]) + js = ["multi.js"] + return forms.Media(js=[static(os.path.join("src", "js", path)) for path in js]) def value_from_datadict(self, data, files, name): values = data.get(name) if not values: return - return list(map(int, values.split(','))) + return list(map(int, values.split(","))) def render(self, name, value, attrs=None, choices=()): - attr_value = ','.join(map(str, value or [])) + attr_value = ",".join(map(str, value or [])) if not attrs: attrs = {} final_attrs = self.build_attrs( - attrs, extra_attrs={'type': 'hidden', 'name': name, 'value': attr_value} + attrs, extra_attrs={"type": "hidden", "name": name, "value": attr_value} ) return mark_safe( 'Expand all' '
      {}
    ' - ''.format( + "".format( name, self.render_options(choices, value), flatatt(final_attrs) ) ) @@ -92,33 +91,33 @@ def render_all_option(self, slug): return ( '' '
    ' - ).format(id_name=slug, label=_('All')) + ).format(id_name=slug, label=_("All")) def render_option(self, selected_choices, option_value, option_label): - input_id = 'id_option_{}'.format(option_value) - attrs = {'id': input_id, 'type': 'checkbox', 'value': option_value} + input_id = "id_option_{}".format(option_value) + attrs = {"id": input_id, "type": "checkbox", "value": option_value} if option_value in selected_choices: - attrs['checked'] = 'checked' + attrs["checked"] = "checked" attrs = self.build_attrs({**attrs}) - return '{}'.format( - flatatt(attrs), flatatt({'for': input_id}), option_label + return "{}".format( + flatatt(attrs), flatatt({"for": input_id}), option_label ) def render_options(self, choices, selected_choices): - separator = ' | ' + separator = " | " choices = sorted( - chain(self.choices, choices), - key=lambda x: x[1].split(separator)[1].lower() + chain(self.choices, choices), key=lambda x: x[1].split(separator)[1].lower() ) grouped = groupby(choices, lambda x: x[1].split(separator)[1]) - rendered_options = '' + rendered_options = "" for group_key, group_choices in grouped: items = list(group_choices) local_values = [item[0] for item in items] local_selected = set(local_values) & set(selected_choices or []) slug = slugify(group_key) label = title(group_key) - rendered_options += mark_safe(""" + rendered_options += mark_safe( + """
  • {title} @@ -129,29 +128,33 @@ def render_options(self, choices, selected_choices): {all}{items}
  • """.format( - slug=slug, - title=label, - selected=len(local_selected), - total=len(local_values), - all=self.render_all_option(slugify(group_key)), - items='
    '.join([ - self.render_option( - local_selected, c[0], c[1].split(separator)[-1] - ) for c in items - ]) - )) + slug=slug, + title=label, + selected=len(local_selected), + total=len(local_values), + all=self.render_all_option(slugify(group_key)), + items="
    ".join( + [ + self.render_option( + local_selected, c[0], c[1].split(separator)[-1] + ) + for c in items + ] + ), + ) + ) return rendered_options class AutocompleteWidget(forms.TextInput): - multivalue_separator = ',' + multivalue_separator = "," def __init__(self, field, admin_site, attrs=None, using=None, **kwargs): self.field = field self.rel = self.field.remote_field - self.multi = kwargs.get('multi', False) - self.request = kwargs.get('request', None) - self.rel_to = kwargs.get('rel_to') or field.remote_field.model + self.multi = kwargs.get("multi", False) + self.request = kwargs.get("request", None) + self.rel_to = kwargs.get("rel_to") or field.remote_field.model self.admin_site = admin_site self.db = using super().__init__(attrs) @@ -164,29 +167,29 @@ def can_edit(self): @property def can_add(self): - return self.admin_site._registry[self.rel_to].has_add_permission( - self.request - ) + return self.admin_site._registry[self.rel_to].has_add_permission(self.request) @property def media(self): - res = forms.Media(js=[ - os.path.join('src', 'js', 'ralph-autocomplete.js'), - 'admin/js/core.js', - ]) + res = forms.Media( + js=[ + os.path.join("src", "js", "ralph-autocomplete.js"), + "admin/js/core.js", + ] + ) return res def get_url_parameters(self): params = { TO_FIELD_VAR: self.rel.get_related_field().name, } - return '?' + parse.urlencode(params) + return "?" + parse.urlencode(params) def get_related_url(self, info, action, *args): return reverse( "admin:%s_%s_%s" % (info + (action,)), current_app=self.admin_site.name, - args=args + args=args, ) def get_prefetch_data(self, value): @@ -214,27 +217,23 @@ def _get_model_search_fields(self, model): try: field = get_field_by_relation_path(model, field_name) key = str(model._meta.verbose_name) - search_fields_tooltip[key].append( - str(field.verbose_name) - ) + search_fields_tooltip[key].append(str(field.verbose_name)) except FieldDoesNotExist as e: logger.error(e) return search_fields_tooltip def get_search_fields(self): - polymorphic_descendants = getattr( - self.rel_to, '_polymorphic_descendants', [] - ) + polymorphic_descendants = getattr(self.rel_to, "_polymorphic_descendants", []) if polymorphic_descendants: # Check if model after which we are looking for is polymorphic # if they are also looking for the models of its dependencies # or by limit_models defined in model polymorphic_models = polymorphic_descendants - limit_models = getattr(self.field, 'limit_models', []) + limit_models = getattr(self.field, "limit_models", []) if limit_models: polymorphic_models = [ - apps.get_model(*i.split('.')) for i in limit_models + apps.get_model(*i.split(".")) for i in limit_models ] search_fields_tooltip = defaultdict(list) @@ -243,73 +242,72 @@ def get_search_fields(self): search_fields_tooltip.update(found) else: - search_fields_tooltip = self._get_model_search_fields( - self.rel_to - ) + search_fields_tooltip = self._get_model_search_fields(self.rel_to) return search_fields_tooltip def render_search_fields_info(self, search_fields): - rows = ['Search by:\n'] + rows = ["Search by:\n"] for model, fields in search_fields.items(): rows.append("{}:\n".format(model.capitalize())) for field in fields: rows.append("- {}\n".format(field)) - return ''.join(rows) + return "".join(rows) def render(self, name, value, attrs=None, renderer=None): - model_options = ( - self.rel_to._meta.app_label, self.rel_to._meta.model_name - ) + model_options = (self.rel_to._meta.app_label, self.rel_to._meta.model_name) original_value = copy.copy(value) if attrs is None: attrs = {} - attrs['name'] = name + attrs["name"] = name if self.multi: value = value or [] - attrs['multi'] = 'true' - value = self.multivalue_separator.join( - force_text(v) for v in value - ) + attrs["multi"] = "true" + value = self.multivalue_separator.join(force_text(v) for v in value) else: value = value or "" search_fields = self.get_search_fields() - search_fields_info = self.render_search_fields_info( - dict(search_fields) - ) + search_fields_info = self.render_search_fields_info(dict(search_fields)) if self.rel_to in self.admin_site._registry: - related_url = reverse( - 'admin:%s_%s_changelist' % ( - self.rel_to._meta.app_label, - self.rel_to._meta.model_name, + related_url = ( + reverse( + "admin:%s_%s_changelist" + % ( + self.rel_to._meta.app_label, + self.rel_to._meta.model_name, + ), + current_app=self.admin_site.name, + ) + + self.get_url_parameters() + ) + + context = RenderContext( + { + "model": str(self.rel_to._meta.verbose_name), + "data_suggest_url": reverse( + "autocomplete-list", + kwargs={ + "app": self.field.remote_field.related_model._meta.app_label, + "model": self.field.remote_field.related_model._meta.model_name, + "field": self.field.name, + }, ), - current_app=self.admin_site.name, - ) + self.get_url_parameters() - - context = RenderContext({ - 'model': str(self.rel_to._meta.verbose_name), - 'data_suggest_url': reverse( - 'autocomplete-list', kwargs={ - 'app': self.field.remote_field.related_model._meta.app_label, - 'model': self.field.remote_field.related_model._meta.model_name, - 'field': self.field.name - } - ), - 'data_details_url': reverse( - 'admin:{}_{}_autocomplete_details'.format(*model_options) - ), - 'name': name or "", - 'value': value, - 'attrs': flatatt(attrs), - 'related_url': related_url, - 'search_fields_info': search_fields_info, - 'prefetch_data': self.get_prefetch_data(original_value) - }) + "data_details_url": reverse( + "admin:{}_{}_autocomplete_details".format(*model_options) + ), + "name": name or "", + "value": value, + "attrs": flatatt(attrs), + "related_url": related_url, + "search_fields_info": search_fields_info, + "prefetch_data": self.get_prefetch_data(original_value), + } + ) info = (self.rel_to._meta.app_label, self.rel_to._meta.model_name) - is_polymorphic = getattr(self.rel_to, 'is_polymorphic', False) + is_polymorphic = getattr(self.rel_to, "is_polymorphic", False) if not is_polymorphic and self.can_add: - context['add_related_url'] = self.get_related_url(info, 'add') - template = loader.get_template('admin/widgets/autocomplete.html') + context["add_related_url"] = self.get_related_url(info, "add") + template = loader.get_template("admin/widgets/autocomplete.html") return template.render(context.flatten()) diff --git a/src/ralph/api/__init__.py b/src/ralph/api/__init__.py index a797c1cadc..a25eed24a1 100644 --- a/src/ralph/api/__init__.py +++ b/src/ralph/api/__init__.py @@ -3,8 +3,8 @@ from ralph.api.routers import router __all__ = [ - 'RalphAPISerializer', - 'RalphAPIViewSet', - 'RalphReadOnlyAPIViewSet', - 'router', + "RalphAPISerializer", + "RalphAPIViewSet", + "RalphReadOnlyAPIViewSet", + "router", ] diff --git a/src/ralph/api/fields.py b/src/ralph/api/fields.py index f98d16b6ac..2d25dbf3d1 100644 --- a/src/ralph/api/fields.py +++ b/src/ralph/api/fields.py @@ -1,19 +1,14 @@ from collections import OrderedDict -from rest_framework.fields import ( - ChoiceField, - Field, - MultipleChoiceField, - ReadOnlyField -) +from rest_framework.fields import ChoiceField, Field, MultipleChoiceField, ReadOnlyField class StrField(Field): def __init__(self, **kwargs): - self._show_type = kwargs.pop('show_type', False) - kwargs['read_only'] = True - if 'label' not in kwargs: - kwargs['label'] = '__str__' + self._show_type = kwargs.pop("show_type", False) + kwargs["read_only"] = True + if "label" not in kwargs: + kwargs["label"] = "__str__" super().__init__(**kwargs) def get_attribute(self, obj): @@ -22,7 +17,7 @@ def get_attribute(self, obj): def to_representation(self, obj): if self._show_type: - return '{}: {}'.format(obj._meta.verbose_name, str(obj)) + return "{}: {}".format(obj._meta.verbose_name, str(obj)) else: return str(obj) @@ -37,6 +32,7 @@ class ReversedChoiceField(ChoiceField): This field works perfectly with `dj.choices.Choices`. """ + def __init__(self, choices, **kwargs): super(ReversedChoiceField, self).__init__(choices, **kwargs) # mapping by value @@ -69,8 +65,9 @@ class ModelMultipleChoiceField(MultipleChoiceField): Changes list of integer data to Django Model queryset """ + def __init__(self, *args, **kwargs): - self.model = kwargs['choices'].queryset.model + self.model = kwargs["choices"].queryset.model super().__init__(*args, **kwargs) def to_internal_value(self, data): @@ -85,9 +82,9 @@ class AbsoluteUrlField(ReadOnlyField): """ def get_attribute(self, obj): - request = self.context.get('request', None) - obj_url_func = getattr(obj, 'get_absolute_url', None) - value = '' + request = self.context.get("request", None) + obj_url_func = getattr(obj, "get_absolute_url", None) + value = "" if request and obj_url_func: value = request.build_absolute_uri(obj_url_func()) return value diff --git a/src/ralph/api/filters.py b/src/ralph/api/filters.py index 4e6d6e10c7..c6ea67f816 100644 --- a/src/ralph/api/filters.py +++ b/src/ralph/api/filters.py @@ -18,8 +18,8 @@ logger = logging.getLogger(__name__) -TRUE_VALUES = dict.fromkeys([1, '1', 'true', 'True', 'yes'], True) -FALSE_VALUES = dict.fromkeys([0, '0', 'false', 'False', 'no'], False) +TRUE_VALUES = dict.fromkeys([1, "1", "true", "True", "yes"], True) +FALSE_VALUES = dict.fromkeys([0, "0", "false", "False", "no"], False) BOOL_VALUES = TRUE_VALUES.copy() BOOL_VALUES.update(FALSE_VALUES) @@ -41,8 +41,9 @@ class AdditionalDjangoFilterBackend(DjangoFilterBackend): Allows to spcify additional FilterSet for viewset (besides standard one, which uses fields from `filter_fields` property. """ + def get_filter_class(self, view, queryset=None): - return getattr(view, 'additional_filter_class', None) + return getattr(view, "additional_filter_class", None) class TagsFilterBackend(BaseFilterBackend): @@ -50,6 +51,7 @@ class TagsFilterBackend(BaseFilterBackend): Filter queryset by tags. Multiple tags could be specified in url query: `?tag=abc&tag=def&tag=123`. """ + def _handle_tags_filter(self, queryset, tags): query = models.Q() for tag in tags: @@ -58,7 +60,7 @@ def _handle_tags_filter(self, queryset, tags): return queryset def filter_queryset(self, request, queryset, view): - tags = request.query_params.getlist('tag') + tags = request.query_params.getlist("tag") if tags and issubclass(queryset.model, TaggableMixin): queryset = self._handle_tags_filter(queryset, tags) return queryset @@ -68,31 +70,30 @@ class ImportedIdFilterBackend(BaseFilterBackend): """ Filter by imported object id """ + def filter_queryset(self, request, queryset, view): for param_name, field_name, use_content_type in [ - ('_imported_object_id', 'old_object_pk', True), - ('_ralph2_ci_uid', 'old_ci_uid', False), - ('_ralph2_ci_uid__startswith', 'old_ci_uid__startswith', False), + ("_imported_object_id", "old_object_pk", True), + ("_ralph2_ci_uid", "old_ci_uid", False), + ("_ralph2_ci_uid__startswith", "old_ci_uid__startswith", False), ]: param_value = request.query_params.get(param_name) if param_value: logger.debug( - 'Processing imported id query param {}:{}'.format( + "Processing imported id query param {}:{}".format( param_name, param_value ) ) query_params = {field_name: param_value} if use_content_type: - query_params['content_type'] = ContentType.objects.get_for_model( # noqa + query_params["content_type"] = ContentType.objects.get_for_model( # noqa queryset.model ) - logger.debug( - 'Filtering imported object by {}'.format(query_params) - ) + logger.debug("Filtering imported object by {}".format(query_params)) try: imported_objects_pks = ImportedObjects.objects.filter( **query_params - ).values_list('object_pk', flat=True) + ).values_list("object_pk", flat=True) except ImportedObjects.DoesNotExist: return queryset.model.objects.none() else: @@ -110,9 +111,8 @@ class ExtendedFiltersBackend(BaseFilterBackend): using `name` filter (query param), `asset_hostname` and `ip_address` will be filtered by. """ - def _handle_extended_filters( - self, request, queryset, extended_filter_fields - ): + + def _handle_extended_filters(self, request, queryset, extended_filter_fields): for field, field_filters in extended_filter_fields.items(): value = request.query_params.get(field, None) if value: @@ -126,9 +126,9 @@ def filter_queryset(self, request, queryset, view): """ Resolve extended filters """ - extended_filter_fields = getattr(view, 'extended_filter_fields', {}) + extended_filter_fields = getattr(view, "extended_filter_fields", {}) if extended_filter_fields: - logger.debug('Applying ExtendedFiltersBackend filters') + logger.debug("Applying ExtendedFiltersBackend filters") queryset = self._handle_extended_filters( request, queryset, extended_filter_fields ) @@ -141,36 +141,74 @@ class LookupFilterBackend(BaseFilterBackend): This filter supports also lookups in extended filters. """ + # allowed lookups depending on field type (using Django's __ convention) # for other types of fields, only strict lookup is allowed field_type_lookups = { # TODO: in and range filters are not working (some iterable is required) models.IntegerField: { - 'lte', 'gte', 'lt', 'gt', 'exact', 'in', 'range', 'isnull' + "lte", + "gte", + "lt", + "gt", + "exact", + "in", + "range", + "isnull", }, models.CharField: { - 'startswith', 'istartswith', 'endswith', 'icontains', 'contains', - 'in', 'iendswith', 'isnull', 'regex', 'iregex' + "startswith", + "istartswith", + "endswith", + "icontains", + "contains", + "in", + "iendswith", + "isnull", + "regex", + "iregex", }, models.DateField: { - 'year', 'month', 'day', 'week_day', 'range', 'isnull', 'lte', - 'gte', 'lt', 'gt' + "year", + "month", + "day", + "week_day", + "range", + "isnull", + "lte", + "gte", + "lt", + "gt", }, models.DateTimeField: { - 'year', 'month', 'day', 'week_day', 'hour', 'minute', 'second', - 'range', 'isnull', 'lte', 'gte', 'lt', 'gt' + "year", + "month", + "day", + "week_day", + "hour", + "minute", + "second", + "range", + "isnull", + "lte", + "gte", + "lt", + "gt", }, models.DecimalField: { - 'lte', 'gte', 'lt', 'gt', 'exact', 'in', 'range', 'isnull' + "lte", + "gte", + "lt", + "gt", + "exact", + "in", + "range", + "isnull", }, - models.AutoField: { - 'startswith', 'exact' - } + models.AutoField: {"startswith", "exact"}, } - def _validate_single_query_lookup( - self, model, model_field_name, lookup, value - ): + def _validate_single_query_lookup(self, model, model_field_name, lookup, value): """ Validate single query param lookup. @@ -185,35 +223,35 @@ def _validate_single_query_lookup( field path is not valid or lookup for field is not valid. """ result = {} - logger.debug('Validating {}__{} lookup for model {}; value: {}'.format( - model_field_name, lookup, model, value - )) - try: - model_field = get_field_by_relation_path( - model, model_field_name + logger.debug( + "Validating {}__{} lookup for model {}; value: {}".format( + model_field_name, lookup, model, value ) + ) + try: + model_field = get_field_by_relation_path(model, model_field_name) except FieldDoesNotExist: - logger.debug( - '{} not found for model {}'.format(model_field_name, model) - ) + logger.debug("{} not found for model {}".format(model_field_name, model)) else: field_lookups = set() # process every class from which field is inheriting for cl in inspect.getmro(model_field.__class__): field_lookups |= self.field_type_lookups.get(cl, set()) - logger.debug('Available lookups for {}.{} : {}'.format( - model, model_field_name, field_lookups - )) + logger.debug( + "Available lookups for {}.{} : {}".format( + model, model_field_name, field_lookups + ) + ) if lookup in field_lookups: - if lookup == 'isnull': + if lookup == "isnull": if value not in BOOL_VALUES: logger.debug( - 'Unknown value for isnull filter: {}'.format(value) + "Unknown value for isnull filter: {}".format(value) ) return {} else: value = BOOL_VALUES[value] - result = {'{}__{}'.format(model_field_name, lookup): value} + result = {"{}__{}".format(model_field_name, lookup): value} return result def _validate_query_lookups( @@ -239,55 +277,56 @@ def _validate_query_lookups( result = [] kw_result = {} logger.debug( - 'Processing {} filters with filter fields={} and extended filter ' - 'fields={}'.format(model, filter_fields, extended_filter_fields) + "Processing {} filters with filter fields={} and extended filter " + "fields={}".format(model, filter_fields, extended_filter_fields) ) for field_name, value in request.query_params.items(): - logger.debug( - 'Processing query param {}:{}'.format(field_name, value) - ) - model_field_name, _, lookup = field_name.rpartition('__') + logger.debug("Processing query param {}:{}".format(field_name, value)) + model_field_name, _, lookup = field_name.rpartition("__") # try if this field search could be expanded to other fields extended_filters = {} - for extended_field_name in extended_filter_fields.get( - model_field_name, [] - ): + for extended_field_name in extended_filter_fields.get(model_field_name, []): extended_filters.update( self._validate_single_query_lookup( - model, - extended_field_name, - lookup, - value + model, extended_field_name, lookup, value ) ) if extended_filters: - logger.debug('Using {} extended filters for query {}:{}'.format( - extended_filters, field_name, value - )) - result.append(reduce( - operator.or_, - [models.Q(**{k: v}) for k, v in extended_filters.items()] - )) + logger.debug( + "Using {} extended filters for query {}:{}".format( + extended_filters, field_name, value + ) + ) + result.append( + reduce( + operator.or_, + [models.Q(**{k: v}) for k, v in extended_filters.items()], + ) + ) # skip if field is not available to filter for if model_field_name in filter_fields: filters = self._validate_single_query_lookup( model, model_field_name, lookup, value ) - logger.debug('Using {} filters for query {}:{}'.format( - filters, field_name, value - )) + logger.debug( + "Using {} filters for query {}:{}".format( + filters, field_name, value + ) + ) kw_result.update(filters) return result, kw_result def filter_queryset(self, request, queryset, view): lookups, kw_lookups = self._validate_query_lookups( - queryset.model, request, view.filter_fields, - getattr(view, 'extended_filter_fields', {}) + queryset.model, + request, + view.filter_fields, + getattr(view, "extended_filter_fields", {}), ) if lookups or kw_lookups: - logger.debug('Applying LookupFilterBackend filters') + logger.debug("Applying LookupFilterBackend filters") queryset = queryset.filter(*lookups, **kw_lookups) return queryset @@ -296,9 +335,8 @@ class PolymorphicDescendantsFilterBackend(LookupFilterBackend): """ Filter descendants of polymorphic models (especially by extended filters). """ - def _process_model( - self, model, request, filter_fields, extended_filter_fields - ): + + def _process_model(self, model, request, filter_fields, extended_filter_fields): ids = set() is_lookup_used = False lookups, kw_lookups = self._validate_query_lookups( @@ -306,14 +344,14 @@ def _process_model( ) if lookups or kw_lookups: is_lookup_used = True - ids = set(model.objects.filter( - *lookups, **kw_lookups - ).values_list('pk', flat=True)) + ids = set( + model.objects.filter(*lookups, **kw_lookups).values_list( + "pk", flat=True + ) + ) return ids, is_lookup_used - def _get_polymorphic_ids( - self, base_model, polymorphic_models, request, view - ): + def _get_polymorphic_ids(self, base_model, polymorphic_models, request, view): """ Returns ids of polymorphic objects based on query filters. @@ -335,8 +373,10 @@ def _get_polymorphic_ids( # process base model # used only with extended filters model_ids, model_is_lookup_used = self._process_model( - base_model, request, view.filter_fields, - getattr(view, 'extended_filter_fields', {}) + base_model, + request, + view.filter_fields, + getattr(view, "extended_filter_fields", {}), ) ids |= model_ids is_lookup_used |= model_is_lookup_used @@ -345,7 +385,7 @@ def _get_polymorphic_ids( model_viewset = view._viewsets_registry.get(model) if model_viewset: # get filters which are applicable to descdenant type - filter_fields = getattr(model_viewset, 'filter_fields', []) + filter_fields = getattr(model_viewset, "filter_fields", []) if not filter_fields: # if not filter_fields from API viewset get fields # from django model admin @@ -360,15 +400,13 @@ def _get_polymorphic_ids( def filter_queryset(self, request, queryset, view): polymorphic_descendants = getattr( - queryset.model, '_polymorphic_descendants', [] + queryset.model, "_polymorphic_descendants", [] ) if polymorphic_descendants: ids, is_lookup_used = self._get_polymorphic_ids( queryset.model, polymorphic_descendants, request, view ) if is_lookup_used: - logger.debug( - 'Applying PolymorphicDescendantsFilterBackend filters' - ) + logger.debug("Applying PolymorphicDescendantsFilterBackend filters") queryset = queryset.filter(pk__in=list(ids)) return queryset diff --git a/src/ralph/api/permissions.py b/src/ralph/api/permissions.py index ed5a493e3b..754d76690d 100644 --- a/src/ralph/api/permissions.py +++ b/src/ralph/api/permissions.py @@ -6,11 +6,9 @@ class IsSuperuserOrReadonly(BasePermission): """ Allow only superuser to save. Every other user has readonly rights. """ + def has_permission(self, request, view): return super().has_permission(request, view) and ( - request.method in SAFE_METHODS or - ( - request.user and - request.user.is_superuser - ) + request.method in SAFE_METHODS + or (request.user and request.user.is_superuser) ) diff --git a/src/ralph/api/relations.py b/src/ralph/api/relations.py index a8d9acad40..1b583651ff 100644 --- a/src/ralph/api/relations.py +++ b/src/ralph/api/relations.py @@ -8,7 +8,6 @@ class RalphRelatedField(QuerysetRelatedMixin, relations.PrimaryKeyRelatedField): class RalphHyperlinkedRelatedField( - QuerysetRelatedMixin, - relations.HyperlinkedRelatedField + QuerysetRelatedMixin, relations.HyperlinkedRelatedField ): pass diff --git a/src/ralph/api/routers.py b/src/ralph/api/routers.py index 54684c7086..ff762ea41e 100644 --- a/src/ralph/api/routers.py +++ b/src/ralph/api/routers.py @@ -15,6 +15,7 @@ class RalphRouter(NestedCustomFieldsRouterMixin, routers.DefaultRouter): Acts like DefaultRouter + checks if user has permissions to see viewset. Viewsets for which user doesn't have permissions are hidden in root view. """ + # skip .json style formatting suffixes in urls include_format_suffixes = False @@ -22,9 +23,7 @@ def get_api_root_view(self, api_urls=None): api_root_dict = {} list_name = self.routes[0].name for prefix, viewset, basename in self.registry: - api_root_dict[prefix] = ( - list_name.format(basename=basename), viewset - ) + api_root_dict[prefix] = (list_name.format(basename=basename), viewset) # present resources in alphabetical order (sort by key, which is url) api_root_dict = OrderedDict(sorted(api_root_dict.items())) from rest_framework import views @@ -42,14 +41,14 @@ def get(self, request, *args, **kwargs): if not self._check_viewset_permissions(request, viewset): continue if namespace: - url_name = namespace + ':' + url_name + url_name = namespace + ":" + url_name try: ret[key] = reverse( url_name, args=args, kwargs=kwargs, request=request, - format=kwargs.get('format', None) + format=kwargs.get("format", None), ) except NoReverseMatch: continue diff --git a/src/ralph/api/serializers.py b/src/ralph/api/serializers.py index 688599ab06..ef74b9bed7 100644 --- a/src/ralph/api/serializers.py +++ b/src/ralph/api/serializers.py @@ -9,33 +9,30 @@ from django.db.models import Q from django.db.models.fields import exceptions from rest_framework import permissions, relations, serializers -from rest_framework.exceptions import \ - ValidationError as RestFrameworkValidationError +from rest_framework.exceptions import ValidationError as RestFrameworkValidationError from rest_framework.settings import api_settings from rest_framework.utils import model_meta from reversion import revisions as reversion -from taggit_serializer.serializers import ( - TaggitSerializer, - TagListSerializerField -) +from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField from ralph.api.fields import AbsoluteUrlField, ReversedChoiceField from ralph.api.relations import RalphHyperlinkedRelatedField, RalphRelatedField from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TaggableMixin from ralph.lib.permissions.api import ( PermissionsPerFieldSerializerMixin, - RelatedObjectsPermissionsSerializerMixin + RelatedObjectsPermissionsSerializerMixin, ) logger = logging.getLogger(__name__) -NESTED_SERIALIZER_FIELDS_BLACKLIST = ['content_type', 'password'] +NESTED_SERIALIZER_FIELDS_BLACKLIST = ["content_type", "password"] class AdditionalLookupRelatedField(serializers.PrimaryKeyRelatedField): """ Allows to lookup related field (foreign key) by fields other than pk. """ + def __init__(self, lookup_fields, *args, **kwargs): self.lookup_fields = lookup_fields super().__init__(*args, **kwargs) @@ -51,9 +48,9 @@ def to_internal_value(self, data): try: return self.get_queryset().get(reduce(operator.or_, query)) except ObjectDoesNotExist: - self.fail('does_not_exist', pk_value=data) + self.fail("does_not_exist", pk_value=data) except (TypeError, ValueError): - self.fail('incorrect_type', data_type=type(data).__name__) + self.fail("incorrect_type", data_type=type(data).__name__) class DeclaredFieldsMetaclass(serializers.SerializerMetaclass): @@ -63,24 +60,25 @@ class DeclaredFieldsMetaclass(serializers.SerializerMetaclass): When serializer's model inherits from `ralph.lib.mixins.models.TaggableMixin`, tags field is attached. """ + def __new__(cls, name, bases, attrs): - meta = attrs.get('Meta') - model = getattr(meta, 'model', None) - fields = getattr(meta, 'fields', None) + meta = attrs.get("Meta") + model = getattr(meta, "model", None) + fields = getattr(meta, "fields", None) if ( - model and - issubclass(model, TaggableMixin) and - not getattr(attrs.get('Meta'), '_skip_tags_field', False) + model + and issubclass(model, TaggableMixin) + and not getattr(attrs.get("Meta"), "_skip_tags_field", False) ): - attrs['tags'] = TagListSerializerField(required=False) - attrs['prefetch_related'] = ( - list(attrs.get('prefetch_related', [])) + ['tags'] - ) + attrs["tags"] = TagListSerializerField(required=False) + attrs["prefetch_related"] = list(attrs.get("prefetch_related", [])) + [ + "tags" + ] if model and issubclass(model, AdminAbsoluteUrlMixin): - attrs['ui_url'] = AbsoluteUrlField() + attrs["ui_url"] = AbsoluteUrlField() if fields and isinstance(fields, (list, tuple)): - meta.fields += ('ui_url',) + meta.fields += ("ui_url",) return super().__new__(cls, name, bases, attrs) @@ -88,7 +86,7 @@ class RalphAPISerializerMixin( TaggitSerializer, RelatedObjectsPermissionsSerializerMixin, PermissionsPerFieldSerializerMixin, - metaclass=DeclaredFieldsMetaclass # noqa + metaclass=DeclaredFieldsMetaclass, # noqa ): """ Mix used in Ralph API serializers features: @@ -99,6 +97,7 @@ class RalphAPISerializerMixin( * use `ReversedChoiceField` as default serializer for choice field * request and user object easily accessible in each related serializer """ + # This switch disable `url` fields in serializers # Ralph uses serializers mainly with http requests, but occasionally we # need to use Ralph serializers with django signals (if so there is no @@ -113,7 +112,10 @@ def serializer_related_field(self): (contains url to related object). When it's not safe request (ex. POST), serializer expect to pass only PK for related object. """ - if self.context.get('request') and self.context['request'].method in permissions.SAFE_METHODS: # noqa + if ( + self.context.get("request") + and self.context["request"].method in permissions.SAFE_METHODS + ): # noqa return RalphHyperlinkedRelatedField return RalphRelatedField @@ -126,9 +128,8 @@ def get_default_field_names(self, declared_fields, model_info): included in `rest_framework.serializers.HyperlinkedModelSerializer` by default). """ - return ( - [model_info.pk.name] + - super().get_default_field_names(declared_fields, model_info) + return [model_info.pk.name] + super().get_default_field_names( + declared_fields, model_info ) def get_fields(self, *args, **kwargs): @@ -137,9 +138,9 @@ def get_fields(self, *args, **kwargs): """ fields = super().get_fields(*args, **kwargs) if ( - self.skip_url_when_no_request and - not self.context.get('request') and - api_settings.URL_FIELD_NAME in fields + self.skip_url_when_no_request + and not self.context.get("request") + and api_settings.URL_FIELD_NAME in fields ): del fields[api_settings.URL_FIELD_NAME] @@ -157,8 +158,8 @@ def build_field(self, field_name, info, model_class, nested_depth): field_name, info, model_class, nested_depth ) if issubclass(field_class, serializers.BaseSerializer): - field_kwargs.setdefault('context', {})['request'] = ( - self.context.get('request') + field_kwargs.setdefault("context", {})["request"] = self.context.get( + "request" ) return field_class, field_kwargs @@ -166,6 +167,7 @@ def build_nested_field(self, field_name, relation_info, nested_depth): """ Nested serializer is inheriting from `RalphAPISerializer`. """ + class NestedMeta: model = relation_info.related_model depth = nested_depth - 1 @@ -203,8 +205,8 @@ def _save_history(self) -> bool: def save(self): if self._save_history: with transaction.atomic(), reversion.create_revision(): - reversion.set_comment('API Save') - reversion.set_user(self.context['request'].user) + reversion.set_comment("API Save") + reversion.set_user(self.context["request"].user) return super().save() else: return super().save() @@ -213,7 +215,7 @@ def save(self): class RalphAPISaveSerializer( TaggitSerializer, ReversionHistoryAPISerializerMixin, - metaclass=DeclaredFieldsMetaclass + metaclass=DeclaredFieldsMetaclass, ): serializer_choice_field = ReversedChoiceField serializer_related_field = relations.PrimaryKeyRelatedField @@ -231,7 +233,7 @@ def build_field(self, *args, **kwargs): # TODO: autocomplete field # http://www.django-rest-framework.org/topics/browsable-api/#customizing if issubclass(field_class, relations.RelatedField): - field_kwargs.setdefault('style', {})['base_template'] = 'input.html' + field_kwargs.setdefault("style", {})["base_template"] = "input.html" return field_class, field_kwargs def _validate_model_clean(self, attrs): @@ -266,12 +268,12 @@ def _django_validation_error_to_drf_validation_error(self, exc): # ValidationError to display errors per field # (the standard behaviour of DRF is to dump all Django # ValidationErrors into "non_field_errors" result field) - if hasattr(exc, 'error_dict'): + if hasattr(exc, "error_dict"): return RestFrameworkValidationError(detail=dict(list(exc))) else: - return RestFrameworkValidationError(detail=dict([ - (NON_FIELD_ERRORS, [value]) for value in exc - ])) + return RestFrameworkValidationError( + detail=dict([(NON_FIELD_ERRORS, [value]) for value in exc]) + ) def _extra_instance_validation(self, instance): pass @@ -288,12 +290,11 @@ def validate(self, attrs): class RalphAPISerializerMetaclass(DeclaredFieldsMetaclass): def __new__(cls, name, bases, attrs): - attrs['_serializers_registry'] = serializers_registry + attrs["_serializers_registry"] = serializers_registry new_cls = super().__new__(cls, name, bases, attrs) - meta = getattr(new_cls, 'Meta', None) - if ( - getattr(meta, 'model', None) and - not getattr(meta, 'exclude_from_registry', False) + meta = getattr(new_cls, "Meta", None) + if getattr(meta, "model", None) and not getattr( + meta, "exclude_from_registry", False ): serializers_registry[meta.model] = new_cls return new_cls @@ -302,6 +303,6 @@ def __new__(cls, name, bases, attrs): class RalphAPISerializer( RalphAPISerializerMixin, serializers.HyperlinkedModelSerializer, - metaclass=RalphAPISerializerMetaclass + metaclass=RalphAPISerializerMetaclass, ): pass diff --git a/src/ralph/api/tests/_base.py b/src/ralph/api/tests/_base.py index 96bb497ab8..b8cda55bd3 100644 --- a/src/ralph/api/tests/_base.py +++ b/src/ralph/api/tests/_base.py @@ -15,7 +15,7 @@ class APIPermissionsTestMixin(object): def setUpClass(cls): super().setUpClass() - cls.foo = Foo.objects.create(bar='rab') + cls.foo = Foo.objects.create(bar="rab") def create_user(name, **kwargs): params = dict( @@ -25,20 +25,23 @@ def create_user(name, **kwargs): ) params.update(kwargs) return get_user_model().objects.create(**params) - cls.user1 = create_user('user1') - cls.user2 = create_user('user2') - cls.user3 = create_user('user3') - cls.user_not_staff = create_user('user_not_staff', is_staff=False) + + cls.user1 = create_user("user1") + cls.user2 = create_user("user2") + cls.user3 = create_user("user3") + cls.user_not_staff = create_user("user_not_staff", is_staff=False) def add_perm(user, perm): - user.user_permissions.add(Permission.objects.get( - content_type=ContentType.objects.get_for_model(Foo), - codename=perm - )) - add_perm(cls.user1, 'change_foo') - add_perm(cls.user1, 'delete_foo') - add_perm(cls.user2, 'add_foo') - add_perm(cls.user_not_staff, 'change_foo') + user.user_permissions.add( + Permission.objects.get( + content_type=ContentType.objects.get_for_model(Foo), codename=perm + ) + ) + + add_perm(cls.user1, "change_foo") + add_perm(cls.user1, "delete_foo") + add_perm(cls.user2, "add_foo") + add_perm(cls.user_not_staff, "change_foo") class _AssertNumQueriesMoreOrLessContext(CaptureQueriesContext): @@ -53,20 +56,27 @@ def __exit__(self, exc_type, exc_value, traceback): return executed = len(self) self.test_case.assertIn( - executed, self.range, - "%d queries executed, %s expected\nCaptured queries were:\n%s" % ( - executed, self.range, - '\n'.join( - '%d. %s' % (i, query['sql']) for i, query in enumerate(self.captured_queries, start=1) - ) - ) + executed, + self.range, + "%d queries executed, %s expected\nCaptured queries were:\n%s" + % ( + executed, + self.range, + "\n".join( + "%d. %s" % (i, query["sql"]) + for i, query in enumerate(self.captured_queries, start=1) + ), + ), ) + + class RalphAPITestCase(APITestCase): """ Base test for Ralph API Test Case. By default there are some users created. """ + @classmethod def _create_users(cls): def create_user(name, **kwargs): @@ -78,11 +88,9 @@ def create_user(name, **kwargs): params.update(kwargs) return get_user_model().objects.create(**params) - cls.user1 = create_user('user1') - cls.user2 = create_user('user2') - cls.superuser = create_user( - 'superuser', is_staff=True, is_superuser=True - ) + cls.user1 = create_user("user1") + cls.user2 = create_user("user2") + cls.superuser = create_user("superuser", is_staff=True, is_superuser=True) @classmethod def setUpClass(cls): @@ -100,9 +108,17 @@ def get_full_url(self, url): """ # testserver is default name of server using by Django test client # see django/test/client.py for details - return 'http://testserver{}'.format(url) - - def assertQueriesMoreOrLess(self, number: int, plus_minus: int, func=None, *args, using=DEFAULT_DB_ALIAS, **kwargs): + return "http://testserver{}".format(url) + + def assertQueriesMoreOrLess( + self, + number: int, + plus_minus: int, + func=None, + *args, + using=DEFAULT_DB_ALIAS, + **kwargs, + ): conn = connections[using] context = _AssertNumQueriesMoreOrLessContext(self, number, plus_minus, conn) diff --git a/src/ralph/api/tests/api.py b/src/ralph/api/tests/api.py index f589e1dddd..dc7fd696a6 100644 --- a/src/ralph/api/tests/api.py +++ b/src/ralph/api/tests/api.py @@ -9,16 +9,12 @@ class FooSerializer(RalphAPISerializer): __str__ = StrField() - str_with_type = StrField(show_type=True, label='__str2__') + str_with_type = StrField(show_type=True, label="__str2__") class Meta: model = Foo # include view namespace for hyperlinked field - extra_kwargs = { - 'url': { - 'view_name': 'test-ralph-api:foo-detail' - } - } + extra_kwargs = {"url": {"view_name": "test-ralph-api:foo-detail"}} fields = "__all__" @@ -31,11 +27,7 @@ class ManufacturerSerializer(RalphAPISerializer): class Meta: model = TestManufacturer # include view namespace for hyperlinked field - extra_kwargs = { - 'url': { - 'view_name': 'test-ralph-api:manufacturer-detail' - } - } + extra_kwargs = {"url": {"view_name": "test-ralph-api:manufacturer-detail"}} class ManufacturerSerializer2(ManufacturerSerializer): @@ -47,11 +39,7 @@ class CarSerializer(RalphAPISerializer): class Meta: model = Car # include view namespace for hyperlinked field - extra_kwargs = { - 'url': { - 'view_name': 'test-ralph-api:car-detail' - } - } + extra_kwargs = {"url": {"view_name": "test-ralph-api:car-detail"}} depth = 1 fields = "__all__" @@ -70,28 +58,30 @@ class ManufacturerViewSet(RalphAPIViewSet): serializer_class = ManufacturerSerializer save_serializer_class = ManufacturerSerializer2 extended_filter_fields = { - 'some_field': ['name', 'country'], + "some_field": ["name", "country"], } class CarViewSet(RalphAPIViewSet): queryset = Car.objects.all() serializer_class = CarSerializer - filter_fields = ['manufacturer__name'] + filter_fields = ["manufacturer__name"] class BarViewSet(RalphAPIViewSet): queryset = Bar.objects.all() serializer_class = BarSerializer - filter_fields = ['id'] + filter_fields = ["id"] app_name = "test-ralph-api" router = RalphRouter() -router.register(r'foos', FooViewSet) -router.register(r'manufacturers', ManufacturerViewSet) -router.register(r'cars', CarViewSet) -router.register(r'bars', BarViewSet) +router.register(r"foos", FooViewSet) +router.register(r"manufacturers", ManufacturerViewSet) +router.register(r"cars", CarViewSet) +router.register(r"bars", BarViewSet) urlpatterns = [ - url(r'test-ralph-api/', include((router.urls, app_name), namespace='test-ralph-api')), + url( + r"test-ralph-api/", include((router.urls, app_name), namespace="test-ralph-api") + ), ] diff --git a/src/ralph/api/tests/test_fields.py b/src/ralph/api/tests/test_fields.py index a081a26077..534b265804 100644 --- a/src/ralph/api/tests/test_fields.py +++ b/src/ralph/api/tests/test_fields.py @@ -12,25 +12,23 @@ class TestChoices(Choices): _ = Choices.Choice - foo = _('foo11') - bar = _('bar22') + foo = _("foo11") + bar = _("bar22") class TestStrField(RalphTestCase): def setUp(self): - self.foo = Foo(bar='abc') + self.foo = Foo(bar="abc") self.str_field = StrField() self.str_field_with_type = StrField(show_type=True) def test_str_field_representation(self): - self.assertEqual( - self.str_field.to_representation(self.foo), str(self.foo) - ) + self.assertEqual(self.str_field.to_representation(self.foo), str(self.foo)) def test_str_field_with_type(self): self.assertEqual( self.str_field_with_type.to_representation(self.foo), - '{}: {}'.format(Foo._meta.verbose_name, str(self.foo)) + "{}: {}".format(Foo._meta.verbose_name, str(self.foo)), ) @@ -41,24 +39,22 @@ def setUp(self): def test_reversed_choices(self): self.assertEqual( self.reversed_choice_field.reversed_choices, - OrderedDict([ - ('foo11', TestChoices.foo.id), - ('bar22', TestChoices.bar.id) - ]) + OrderedDict([("foo11", TestChoices.foo.id), ("bar22", TestChoices.bar.id)]), ) def test_to_representation_should_return_choice_text(self): self.assertEqual( - self.reversed_choice_field.to_representation(TestChoices.foo.id), - 'foo11' + self.reversed_choice_field.to_representation(TestChoices.foo.id), "foo11" ) def test_to_internal_value_should_map_choice_text_to_id(self): self.assertEqual( - self.reversed_choice_field.to_internal_value('foo11'), + self.reversed_choice_field.to_internal_value("foo11"), TestChoices.foo.id, ) - def test_to_internal_value_with_choice_not_found_should_raise_validation_error(self): # noqa + def test_to_internal_value_with_choice_not_found_should_raise_validation_error( + self, + ): # noqa with self.assertRaises(ValidationError): - self.reversed_choice_field.to_internal_value('foo33') + self.reversed_choice_field.to_internal_value("foo33") diff --git a/src/ralph/api/tests/test_filters.py b/src/ralph/api/tests/test_filters.py index a6bdbd662b..6e9aaa1f16 100644 --- a/src/ralph/api/tests/test_filters.py +++ b/src/ralph/api/tests/test_filters.py @@ -11,14 +11,9 @@ ExtendedFiltersBackend, FALSE_VALUES, LookupFilterBackend, - TRUE_VALUES -) -from ralph.api.tests.api import ( - Bar, - BarViewSet, - ManufacturerViewSet, - TestManufacturer + TRUE_VALUES, ) +from ralph.api.tests.api import Bar, BarViewSet, ManufacturerViewSet, TestManufacturer from ralph.tests import RalphTestCase from ralph.tests.factories import TestManufacturerFactory @@ -27,196 +22,182 @@ class TestExtendedFiltersBackend(RalphTestCase): def setUp(self): super().setUp() self.request_factory = APIRequestFactory() - self.manufacture_1 = TestManufacturerFactory( - name='test', country='Poland' - ) - self.manufacture_2 = TestManufacturerFactory( - name='test2', country='test' - ) - get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' - ) + self.manufacture_1 = TestManufacturerFactory(name="test", country="Poland") + self.manufacture_2 = TestManufacturerFactory(name="test2", country="test") + get_user_model().objects.create_superuser("test", "test@test.test", "test") self.client = APIClient() - self.client.login(username='test', password='test') + self.client.login(username="test", password="test") self.extended_filters_backend = ExtendedFiltersBackend() def test_extended_filter_fields(self): - request = self.request_factory.get('/') - request.query_params = QueryDict(urlencode({'some_field': 'test'})) + request = self.request_factory.get("/") + request.query_params = QueryDict(urlencode({"some_field": "test"})) mvs = ManufacturerViewSet() mvs.request = request - self.assertEqual(len(self.extended_filters_backend.filter_queryset( - request, TestManufacturer.objects.all(), mvs) - ), 2) + self.assertEqual( + len( + self.extended_filters_backend.filter_queryset( + request, TestManufacturer.objects.all(), mvs + ) + ), + 2, + ) - request.query_params = QueryDict(urlencode({'some_field': 'test2'})) + request.query_params = QueryDict(urlencode({"some_field": "test2"})) mvs.request = request - self.assertEqual(len(self.extended_filters_backend.filter_queryset( - request, TestManufacturer.objects.all(), mvs) - ), 1) + self.assertEqual( + len( + self.extended_filters_backend.filter_queryset( + request, TestManufacturer.objects.all(), mvs + ) + ), + 1, + ) class TestLookupFilterBackend(RalphTestCase): def setUp(self): super().setUp() self.request_factory = APIRequestFactory() - get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' - ) + get_user_model().objects.create_superuser("test", "test@test.test", "test") self.client = APIClient() - self.client.login(username='test', password='test') + self.client.login(username="test", password="test") Bar.objects.create( id=999999, - name='Bar11', + name="Bar11", date=date(2015, 3, 1), - price=Decimal('21.4'), - count=1 + price=Decimal("21.4"), + count=1, ) Bar.objects.create( - name='Bar22', - date=date(2014, 4, 1), - price=Decimal('11.4'), - count=2 + name="Bar22", date=date(2014, 4, 1), price=Decimal("11.4"), count=2 ) Bar.objects.create( - name='Bar33', - date=date(2013, 5, 1), - price=Decimal('31.4'), - count=3 - ) - Bar.objects.create( - name='Bar44', - date=None, - price=Decimal('41.4'), - count=4 + name="Bar33", date=date(2013, 5, 1), price=Decimal("31.4"), count=3 ) + Bar.objects.create(name="Bar44", date=None, price=Decimal("41.4"), count=4) self.lookup_filter = LookupFilterBackend() def test_query_filters_charfield(self): - request = self.request_factory.get('/api/bar') + request = self.request_factory.get("/api/bar") bvs = BarViewSet() - request.query_params = QueryDict( - urlencode({'name__icontains': 'bar1'}) - ) + request.query_params = QueryDict(urlencode({"name__icontains": "bar1"})) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 1) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 1 + ) # Failed filter - request.query_params = QueryDict(urlencode({'name__range': 10})) - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 4) + request.query_params = QueryDict(urlencode({"name__range": 10})) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 4 + ) def test_query_filters_decimalfield(self): - request = self.request_factory.get('/api/bar') + request = self.request_factory.get("/api/bar") bvs = BarViewSet() - request.query_params = QueryDict(urlencode({'price__gte': 20})) + request.query_params = QueryDict(urlencode({"price__gte": 20})) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 3) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 3 + ) # Failed filter - request.query_params = QueryDict(urlencode({'price__istartswith': 10})) - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 4) + request.query_params = QueryDict(urlencode({"price__istartswith": 10})) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 4 + ) def test_query_filters_integerfield(self): - request = self.request_factory.get('/api/bar') + request = self.request_factory.get("/api/bar") bvs = BarViewSet() - request.query_params = QueryDict(urlencode({'count__gte': 2})) + request.query_params = QueryDict(urlencode({"count__gte": 2})) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 3) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 3 + ) # Failed filter - request.query_params = QueryDict(urlencode({'count__istartswith': 10})) - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 4) + request.query_params = QueryDict(urlencode({"count__istartswith": 10})) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 4 + ) def test_query_filters_datefield(self): - request = self.request_factory.get('/api/bar') + request = self.request_factory.get("/api/bar") bvs = BarViewSet() - request.query_params = QueryDict(urlencode({'date__year': 2015})) + request.query_params = QueryDict(urlencode({"date__year": 2015})) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 1) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 1 + ) # Failed filter - request.query_params = QueryDict(urlencode({'date__istartswith': 10})) - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 4) + request.query_params = QueryDict(urlencode({"date__istartswith": 10})) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 4 + ) def test_query_filters_datetimefield(self): - request = self.request_factory.get('/api/bar') + request = self.request_factory.get("/api/bar") bvs = BarViewSet() - request.query_params = QueryDict(urlencode( - {'created__year': date.today().year}) + request.query_params = QueryDict( + urlencode({"created__year": date.today().year}) ) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 4) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 4 + ) request.query_params = QueryDict( - urlencode({ - 'date__year': 2014, - 'created__month': date.today().month - }) + urlencode({"date__year": 2014, "created__month": date.today().month}) ) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 1) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 1 + ) # Failed filter - request.query_params = QueryDict( - urlencode({'created__istartswith': 10}) + request.query_params = QueryDict(urlencode({"created__istartswith": 10})) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 4 ) - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 4) def test_query_filters_autofield(self): - request = self.request_factory.get('/api/bar') + request = self.request_factory.get("/api/bar") bvs = BarViewSet() - request.query_params = QueryDict(urlencode({'id__startswith': '99999'})) + request.query_params = QueryDict(urlencode({"id__startswith": "99999"})) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 1) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 1 + ) - request.query_params = QueryDict(urlencode({'id__exact': '999999'})) - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 1) + request.query_params = QueryDict(urlencode({"id__exact": "999999"})) + self.assertEqual( + len(self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs)), 1 + ) def test_query_filters_isnull(self): - request = self.request_factory.get('/api/bar') + request = self.request_factory.get("/api/bar") bvs = BarViewSet() for val in TRUE_VALUES: - request.query_params = QueryDict(urlencode( - {'date__isnull': val}) - ) + request.query_params = QueryDict(urlencode({"date__isnull": val})) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 1) + self.assertEqual( + len( + self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs) + ), + 1, + ) for val in FALSE_VALUES: - request.query_params = QueryDict(urlencode( - {'date__isnull': val}) - ) + request.query_params = QueryDict(urlencode({"date__isnull": val})) bvs.request = request - self.assertEqual(len(self.lookup_filter.filter_queryset( - request, Bar.objects.all(), bvs) - ), 3) + self.assertEqual( + len( + self.lookup_filter.filter_queryset(request, Bar.objects.all(), bvs) + ), + 3, + ) diff --git a/src/ralph/api/tests/test_rendering.py b/src/ralph/api/tests/test_rendering.py index a56d906bbd..7ee89aa47d 100644 --- a/src/ralph/api/tests/test_rendering.py +++ b/src/ralph/api/tests/test_rendering.py @@ -14,14 +14,12 @@ class APIBrowsableClient(APIClient): - renderer_classes_list = ( - 'rest_framework.renderers.BrowsableAPIRenderer', - ) - default_format = 'text/html' + renderer_classes_list = ("rest_framework.renderers.BrowsableAPIRenderer",) + default_format = "text/html" # If you want to test all items in the API, set BROWSE_ALL_API_ITEMS=1 env -BROWSE_ALL_API_ITEMS = os.environ.get('BROWSE_ALL_API_ITEMS', False) +BROWSE_ALL_API_ITEMS = os.environ.get("BROWSE_ALL_API_ITEMS", False) DEFAULT_MAX_QUERIES = 20 # To get this just visit /api in your browser ALL_API_ENDPOINTS = { @@ -108,7 +106,7 @@ class APIBrowsableClient(APIClient): "virtual-server-types": "/api/virtual-server-types/", "virtual-servers": "/api/virtual-servers/", "vulnerabilities": "/api/vulnerabilities/", - "warehouses": "/api/warehouses/" + "warehouses": "/api/warehouses/", } @@ -120,52 +118,52 @@ class RalphAPIRenderingTests(APIPermissionsTestMixin, APITestCase): def setUpClass(cls): super().setUpClass() for factory in FACTORY_MAP.values(): - module_path, factory_class = factory.rsplit( - '.', 1 - ) + module_path, factory_class = factory.rsplit(".", 1) module = import_module(module_path) factory_model = getattr(module, factory_class) factory_model.create_batch(20) cls.user = UserFactory(is_staff=True, is_superuser=True) def test_rendering(self): - url = reverse('test-ralph-api:api-root') + url = reverse("test-ralph-api:api-root") self.client.force_authenticate(self.user1) - response = self.client.get(url, HTTP_ACCEPT='text/html') + response = self.client.get(url, HTTP_ACCEPT="text/html") self.assertEqual(response.status_code, status.HTTP_200_OK) - @data( - *ALL_API_ENDPOINTS.keys() - ) + @data(*ALL_API_ENDPOINTS.keys()) def test_browsable_endpoint(self, model_name): - endpoint, max_queries = ALL_API_ENDPOINTS[model_name] \ - if isinstance(ALL_API_ENDPOINTS[model_name], tuple) \ + endpoint, max_queries = ( + ALL_API_ENDPOINTS[model_name] + if isinstance(ALL_API_ENDPOINTS[model_name], tuple) else (ALL_API_ENDPOINTS[model_name], DEFAULT_MAX_QUERIES) + ) self.client.force_authenticate(self.user) - with CaptureQueriesContext(connections['default']) as cqc: - response = self.client.get(endpoint, HTTP_ACCEPT='text/html') + with CaptureQueriesContext(connections["default"]) as cqc: + response = self.client.get(endpoint, HTTP_ACCEPT="text/html") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertLessEqual(len(cqc.captured_queries), max_queries) - @data( - *ALL_API_ENDPOINTS.keys() - ) + @data(*ALL_API_ENDPOINTS.keys()) def test_json_endpoint(self, model_name): - endpoint, max_queries = ALL_API_ENDPOINTS[model_name] \ - if isinstance(ALL_API_ENDPOINTS[model_name], tuple) \ + endpoint, max_queries = ( + ALL_API_ENDPOINTS[model_name] + if isinstance(ALL_API_ENDPOINTS[model_name], tuple) else (ALL_API_ENDPOINTS[model_name], DEFAULT_MAX_QUERIES) + ) self.client.force_authenticate(self.user) while True: - with CaptureQueriesContext(connections['default']) as cqc: - response = self.client.get(endpoint, HTTP_ACCEPT='application/json') + with CaptureQueriesContext(connections["default"]) as cqc: + response = self.client.get(endpoint, HTTP_ACCEPT="application/json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertGreater(len(response.json()['results']), 0) + self.assertGreater(len(response.json()["results"]), 0) self.assertLessEqual( - len(cqc.captured_queries), max_queries, + len(cqc.captured_queries), + max_queries, msg=f"Too many queries when getting {endpoint}." f"\nQueries count: {len(cqc.captured_queries)}." - "\nQueries:\n" + "\n".join(query['sql'] for query in cqc.captured_queries) + "\nQueries:\n" + + "\n".join(query["sql"] for query in cqc.captured_queries), ) - endpoint = response.json()['next'] + endpoint = response.json()["next"] if not BROWSE_ALL_API_ITEMS or endpoint is None: break diff --git a/src/ralph/api/tests/test_routers.py b/src/ralph/api/tests/test_routers.py index 8cb5b759e6..2d5db83bc9 100644 --- a/src/ralph/api/tests/test_routers.py +++ b/src/ralph/api/tests/test_routers.py @@ -8,22 +8,22 @@ class RalphRouterTests(APIPermissionsTestMixin, APITestCase): def test_router_user_has_access_to_foo(self): - url = reverse('test-ralph-api:api-root') + url = reverse("test-ralph-api:api-root") self.client.force_authenticate(self.user1) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertIn('foos', response.data) + self.assertIn("foos", response.data) def test_router_user_has_not_access_to_foo(self): - url = reverse('test-ralph-api:api-root') + url = reverse("test-ralph-api:api-root") self.client.force_authenticate(self.user3) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertNotIn('foos', response.data) + self.assertNotIn("foos", response.data) def test_router_user_not_staff_has_not_access_to_foo(self): - url = reverse('test-ralph-api:api-root') + url = reverse("test-ralph-api:api-root") self.client.force_authenticate(self.user_not_staff) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - self.assertNotIn('foos', response.data) + self.assertNotIn("foos", response.data) diff --git a/src/ralph/api/tests/test_serializers.py b/src/ralph/api/tests/test_serializers.py index 49fd916681..45221ab38f 100644 --- a/src/ralph/api/tests/test_serializers.py +++ b/src/ralph/api/tests/test_serializers.py @@ -19,26 +19,26 @@ class TestChoices(Choices): _ = Choices.Choice - foo = _('foo11') - bar = _('bar22') + foo = _("foo11") + bar = _("bar22") class TestStrSerialization(RalphAPITestCase): def setUp(self): - self.foo = Foo(bar='abc') + self.foo = Foo(bar="abc") self.request_factory = APIRequestFactory() def test_str_field(self): - request = self.request_factory.get('/api/foos') - serializer = FooSerializer(self.foo, context={'request': request}) - self.assertEqual(serializer.data['__str__'], str(self.foo)) + request = self.request_factory.get("/api/foos") + serializer = FooSerializer(self.foo, context={"request": request}) + self.assertEqual(serializer.data["__str__"], str(self.foo)) def test_str_field_with_type(self): - request = self.request_factory.get('/api/foos') - serializer = FooSerializer(self.foo, context={'request': request}) + request = self.request_factory.get("/api/foos") + serializer = FooSerializer(self.foo, context={"request": request}) self.assertEqual( - serializer.data['str_with_type'], - '{}: {}'.format(Foo._meta.model_name, str(self.foo)) + serializer.data["str_with_type"], + "{}: {}".format(Foo._meta.model_name, str(self.foo)), ) @@ -48,84 +48,62 @@ def setUp(self): self.car = Car(manufacturer=self.manufacturer, name="S", year=2012) self.request_factory = APIRequestFactory() - get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' - ) + get_user_model().objects.create_superuser("test", "test@test.test", "test") self.client = APIClient() - self.client.login(username='test', password='test') + self.client.login(username="test", password="test") def test_get_serializer_related_field_when_safe_request(self): - request = self.request_factory.get('/api/cars') - car_serializer = CarSerializer( - instance=self.car, context={'request': request} - ) + request = self.request_factory.get("/api/cars") + car_serializer = CarSerializer(instance=self.car, context={"request": request}) self.assertEqual( - car_serializer.serializer_related_field, - RalphHyperlinkedRelatedField + car_serializer.serializer_related_field, RalphHyperlinkedRelatedField ) def test_get_serializer_related_field_when_not_safe_request(self): - request = self.request_factory.patch('/api/cars', data={}) - car_serializer = CarSerializer( - instance=self.car, context={'request': request} - ) - self.assertEqual( - car_serializer.serializer_related_field, - RalphRelatedField - ) + request = self.request_factory.patch("/api/cars", data={}) + car_serializer = CarSerializer(instance=self.car, context={"request": request}) + self.assertEqual(car_serializer.serializer_related_field, RalphRelatedField) def test_serializer_request_assigned_to_related_field(self): - request = self.request_factory.patch('/api/cars', data={}) + request = self.request_factory.patch("/api/cars", data={}) request.user = self.user1 - car_serializer = CarSerializer( - instance=self.car, context={'request': request} - ) + car_serializer = CarSerializer(instance=self.car, context={"request": request}) fields = car_serializer.get_fields() - self.assertIs(fields['year'].context['request'], request) - self.assertIs(fields['manufacturer'].context['request'], request) + self.assertIs(fields["year"].context["request"], request) + self.assertIs(fields["manufacturer"].context["request"], request) def test_serializer_request_assigned_to_related_declared_field(self): - request = self.request_factory.patch('/api/cars', data={}) + request = self.request_factory.patch("/api/cars", data={}) request.user = self.user1 - car_serializer = CarSerializer2( - instance=self.car, context={'request': request} - ) + car_serializer = CarSerializer2(instance=self.car, context={"request": request}) fields = car_serializer.get_fields() - self.assertIs(fields['year'].context['request'], request) - self.assertIs(fields['manufacturer'].context['request'], request) + self.assertIs(fields["year"].context["request"], request) + self.assertIs(fields["manufacturer"].context["request"], request) def test_reversion_history_save(self): - response = self.client.post( - '/test-ralph-api/foos/', data={'bar': 'bar_name'} - ) - foo = Foo.objects.get(pk=response.data['id']) + response = self.client.post("/test-ralph-api/foos/", data={"bar": "bar_name"}) + foo = Foo.objects.get(pk=response.data["id"]) history = Version.objects.get_for_object(foo) self.assertEqual(len(history), 1) - self.assertIn('bar_name', history[0].serialized_data) + self.assertIn("bar_name", history[0].serialized_data) response = self.client.patch( - '/test-ralph-api/foos/{}/'.format(foo.id), - data={'bar': 'new_bar'} + "/test-ralph-api/foos/{}/".format(foo.id), data={"bar": "new_bar"} ) - foo = Foo.objects.get(pk=response.data['id']) + foo = Foo.objects.get(pk=response.data["id"]) history = Version.objects.get_for_object(foo) self.assertEqual(len(history), 2) - self.assertIn('new_bar', history[0].serialized_data) + self.assertIn("new_bar", history[0].serialized_data) def test_reversion_history_for_intermediary_model(self): region_pl = RegionFactory() bo_asset = BackOfficeAssetFactory(region=region_pl) licence = LicenceFactory(region=region_pl) - url = reverse('baseobjectlicence-list') - response = self.client.post(url, data={ - 'base_object': bo_asset.id, - 'licence': licence.id - }) - base_object_licence = BaseObjectLicence.objects.get( - pk=response.data['id'] + url = reverse("baseobjectlicence-list") + response = self.client.post( + url, data={"base_object": bo_asset.id, "licence": licence.id} ) + base_object_licence = BaseObjectLicence.objects.get(pk=response.data["id"]) history = Version.objects.get_for_object(base_object_licence) self.assertEqual(len(history), 1) - self.assertIn( - '"licence": {}'.format(licence.id), history[0].serialized_data - ) + self.assertIn('"licence": {}'.format(licence.id), history[0].serialized_data) diff --git a/src/ralph/api/tests/test_viewsets.py b/src/ralph/api/tests/test_viewsets.py index b6d6474f63..d6b83ea844 100644 --- a/src/ralph/api/tests/test_viewsets.py +++ b/src/ralph/api/tests/test_viewsets.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from datetime import date -from decimal import Decimal from django.contrib.auth import get_user_model from rest_framework import relations @@ -12,7 +10,7 @@ CarSerializer, CarViewSet, ManufacturerSerializer2, - ManufacturerViewSet + ManufacturerViewSet, ) from ralph.api.viewsets import RalphAPIViewSet from ralph.tests import RalphTestCase @@ -31,58 +29,54 @@ class TestRalphViewset(RalphTestCase): def setUp(self): super().setUp() self.request_factory = APIRequestFactory() - self.manufacture_1 = TestManufacturerFactory( - name='test', country='Poland' - ) - self.manufacture_2 = TestManufacturerFactory( - name='test2', country='test' - ) - get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' - ) + self.manufacture_1 = TestManufacturerFactory(name="test", country="Poland") + self.manufacture_2 = TestManufacturerFactory(name="test2", country="test") + get_user_model().objects.create_superuser("test", "test@test.test", "test") self.client = APIClient() - self.client.login(username='test', password='test') + self.client.login(username="test", password="test") def test_should_raise_attributeerror_when_ralph_permission_missing(self): with self.assertRaises(AttributeError): ViewsetWithoutRalphPermission() - def test_should_raise_attributeerror_when_permission_for_object_filter_missing(self): # noqa + def test_should_raise_attributeerror_when_permission_for_object_filter_missing( + self, + ): # noqa with self.assertRaises(AttributeError): ViewsetWithoutPermissionsForObjectFilter() def test_get_serializer_class_should_return_base_when_safe_request(self): - request = self.request_factory.get('/') + request = self.request_factory.get("/") cvs = CarViewSet() cvs.request = request self.assertEqual(cvs.get_serializer_class(), CarSerializer) def test_get_serializer_class_should_return_dynamic_when_not_safe_request(self): # noqa - request = self.request_factory.post('/') + request = self.request_factory.post("/") cvs = CarViewSet() cvs.request = request serializer_class = cvs.get_serializer_class() - self.assertEqual(serializer_class.__name__, 'CarSaveSerializer') + self.assertEqual(serializer_class.__name__, "CarSaveSerializer") self.assertEqual(serializer_class.Meta.model, Car) self.assertEqual(serializer_class.Meta.depth, 0) + self.assertEqual(serializer_class.serializer_choice_field, ReversedChoiceField) self.assertEqual( - serializer_class.serializer_choice_field, ReversedChoiceField - ) - self.assertEqual( - serializer_class.serializer_related_field, - relations.PrimaryKeyRelatedField + serializer_class.serializer_related_field, relations.PrimaryKeyRelatedField ) - def test_get_serializer_class_should_return_defined_when_not_safe_request_and_save_serializer_class_defined(self): # noqa - request = self.request_factory.patch('/') + def test_get_serializer_class_should_return_defined_when_not_safe_request_and_save_serializer_class_defined( + self, + ): # noqa + request = self.request_factory.patch("/") mvs = ManufacturerViewSet() mvs.request = request self.assertEqual(mvs.get_serializer_class(), ManufacturerSerializer2) def test_options_filtering(self): - response = self.client.options('/api/manufacturers/') + response = self.client.options("/api/manufacturers/") self.assertCountEqual( - response.data['filtering'], ['name', 'manufacturer_kind'], + response.data["filtering"], + ["name", "manufacturer_kind"], ) @@ -90,6 +84,5 @@ class TestAdminSearchFieldsMixin(RalphTestCase): def test_get_filter_fields_from_admin(self): cvs = CarViewSet() self.assertEqual( - cvs.filter_fields, - ['manufacturer__name', 'name', 'foos__bar', 'year'] + cvs.filter_fields, ["manufacturer__name", "name", "foos__bar", "year"] ) diff --git a/src/ralph/api/utils.py b/src/ralph/api/utils.py index 005944d2a5..b991538d02 100644 --- a/src/ralph/api/utils.py +++ b/src/ralph/api/utils.py @@ -5,7 +5,7 @@ from ralph.admin.sites import ralph_site -logger = logging.getLogger('__name__') +logger = logging.getLogger("__name__") class QuerysetRelatedMixin(object): @@ -15,24 +15,22 @@ class QuerysetRelatedMixin(object): Default select_related is taken from related admin site `list_select_related` attribute. """ + select_related = None prefetch_related = None _skip_admin_list_select_related = False def __init__(self, *args, **kwargs): - self.select_related = kwargs.pop( - 'select_related', - self.select_related - ) or [] - self.prefetch_related = kwargs.pop( - 'prefetch_related', self.prefetch_related - ) or [] - if getattr(self, 'queryset', None) is not None: + self.select_related = kwargs.pop("select_related", self.select_related) or [] + self.prefetch_related = ( + kwargs.pop("prefetch_related", self.prefetch_related) or [] + ) + if getattr(self, "queryset", None) is not None: admin_site = ralph_site._registry.get(self.queryset.model) if ( - admin_site and - not self._skip_admin_list_select_related and - admin_site.list_select_related + admin_site + and not self._skip_admin_list_select_related + and admin_site.list_select_related ): self.select_related.extend(admin_site.list_select_related) super().__init__(*args, **kwargs) @@ -52,6 +50,7 @@ class PolymorphicViewSetMixin(QuerysetRelatedMixin): serializer for this model is used. This ViewSet is working together with `PolymorphicSerializer`. """ + def get_queryset(self): queryset = super().get_queryset() polymorphic_select_related = {} @@ -66,24 +65,21 @@ def get_queryset(self): ) return queryset.polymorphic_select_related( **polymorphic_select_related - ).polymorphic_prefetch_related( - **polymorphic_prefetch_related - ) + ).polymorphic_prefetch_related(**polymorphic_prefetch_related) def get_serializer(self, *args, **kwargs): serializer_class = self.get_serializer_class() - kwargs['context'] = self.get_serializer_context() + kwargs["context"] = self.get_serializer_context() # for single object use dedicated serializer directly # for many objects, `PolymorphicListSerializer` is used underneath - if not kwargs.get('many'): + if not kwargs.get("many"): try: serializer_class = serializer_class._serializers_registry[ args[0].__class__ ] except KeyError: logger.warning( - 'Dedicated serializer not found for %s', - args[0].__class__ + "Dedicated serializer not found for %s", args[0].__class__ ) return serializer_class(*args, **kwargs) @@ -94,8 +90,9 @@ class PolymorphicListSerializer(serializers.ListSerializer): For each instance (model) dedicated `to_representation` of this model serializer is called. """ + def __init__(self, *args, **kwargs): - self.child_serializers = kwargs.pop('child_serializers') + self.child_serializers = kwargs.pop("child_serializers") super().__init__(*args, **kwargs) def to_representation(self, data): @@ -110,6 +107,7 @@ def iterate(): yield {"id": item.id} except Exception: yield {} + return [i for i in iterate()] @@ -120,6 +118,7 @@ class PolymorphicSerializer(serializers.Serializer): The only difference comparing to regular serializer is case with many objects - instead of `ListSerializer`, `PolymorphicListSerializer` is used. """ + @classmethod def many_init(cls, *args, **kwargs): child_serializer = cls(*args, **kwargs) @@ -131,11 +130,16 @@ def many_init(cls, *args, **kwargs): descendant_model, cls )(*args, **kwargs) list_kwargs = { - 'child': child_serializer, - 'child_serializers': child_serializers, + "child": child_serializer, + "child_serializers": child_serializers, } - list_kwargs.update(dict([ - (key, value) for key, value in kwargs.items() - if key in serializers.LIST_SERIALIZER_KWARGS - ])) + list_kwargs.update( + dict( + [ + (key, value) + for key, value in kwargs.items() + if key in serializers.LIST_SERIALIZER_KWARGS + ] + ) + ) return PolymorphicListSerializer(*args, **list_kwargs) diff --git a/src/ralph/api/viewsets.py b/src/ralph/api/viewsets.py index 0895c1458c..a6b1229f68 100644 --- a/src/ralph/api/viewsets.py +++ b/src/ralph/api/viewsets.py @@ -12,15 +12,12 @@ ImportedIdFilterBackend, LookupFilterBackend, PolymorphicDescendantsFilterBackend, - TagsFilterBackend + TagsFilterBackend, ) from ralph.api.serializers import RalphAPISaveSerializer, ReversedChoiceField from ralph.api.utils import QuerysetRelatedMixin from ralph.lib.custom_fields.api import CustomFieldsFilterBackend -from ralph.lib.permissions.api import ( - PermissionsForObjectFilter, - RalphPermission -) +from ralph.lib.permissions.api import PermissionsForObjectFilter, RalphPermission class AdminSearchFieldsMixin(object): @@ -28,6 +25,7 @@ class AdminSearchFieldsMixin(object): Default `filter_fields` ViewSet are search and filter fields from model's related admin site. """ + _skip_admin_search_fields = False _skip_admin_list_filter = False filter_backends = [DjangoFilterBackend] @@ -38,10 +36,8 @@ def __init__(self, *args, **kwargs): def _set_admin_search_fields(self): admin_site = ralph_site._registry.get(self.queryset.model) - filter_fields = list(getattr(self, 'filter_fields', None) or []) - exclude_fields = getattr( - self, 'exclude_filter_fields', [] - ) + filter_fields = list(getattr(self, "filter_fields", None) or []) + exclude_fields = getattr(self, "exclude_filter_fields", []) if admin_site and not self._skip_admin_search_fields: filter_fields.extend(admin_site.search_fields or []) if admin_site and not self._skip_admin_list_filter: @@ -53,11 +49,11 @@ def _set_admin_search_fields(self): if f_name in exclude_fields: continue if inspect.isclass(f) and issubclass(f, SimpleListFilter): - if not hasattr(f, 'field'): + if not hasattr(f, "field"): continue f_name = f.parameter_name filter_fields.append(f_name) - setattr(self, 'filter_fields', filter_fields) + setattr(self, "filter_fields", filter_fields) class RalphAPIViewSetMixin(QuerysetRelatedMixin, AdminSearchFieldsMixin): @@ -65,12 +61,17 @@ class RalphAPIViewSetMixin(QuerysetRelatedMixin, AdminSearchFieldsMixin): Ralph API default viewset. Provides object-level permissions checking and model permissions checking (using Django-admin permissions). """ + filter_backends = AdminSearchFieldsMixin.filter_backends + [ - PermissionsForObjectFilter, filters.OrderingFilter, - ExtendedFiltersBackend, LookupFilterBackend, - PolymorphicDescendantsFilterBackend, TagsFilterBackend, - ImportedIdFilterBackend, AdditionalDjangoFilterBackend, - CustomFieldsFilterBackend + PermissionsForObjectFilter, + filters.OrderingFilter, + ExtendedFiltersBackend, + LookupFilterBackend, + PolymorphicDescendantsFilterBackend, + TagsFilterBackend, + ImportedIdFilterBackend, + AdditionalDjangoFilterBackend, + CustomFieldsFilterBackend, ] permission_classes = [RalphPermission] save_serializer_class = None @@ -88,12 +89,10 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # check if required permissions and filters classes are present if RalphPermission not in self.permission_classes: - raise AttributeError( - 'RalphPermission missing in permission_classes' - ) + raise AttributeError("RalphPermission missing in permission_classes") if PermissionsForObjectFilter not in self.filter_backends: raise AttributeError( - 'PermissionsForObjectFilter missing in filter_backends' + "PermissionsForObjectFilter missing in filter_backends" ) def get_serializer_class(self): @@ -116,13 +115,13 @@ class Meta(base_serializer.Meta): depth = 0 return type( - '{}SaveSerializer'.format(Meta.model.__name__), + "{}SaveSerializer".format(Meta.model.__name__), (RalphAPISaveSerializer,), { - 'Meta': Meta, - 'serializer_choice_field': ReversedChoiceField, - 'serializer_related_field': relations.PrimaryKeyRelatedField - } + "Meta": Meta, + "serializer_choice_field": ReversedChoiceField, + "serializer_related_field": relations.PrimaryKeyRelatedField, + }, ) return base_serializer @@ -132,22 +131,20 @@ class Meta(base_serializer.Meta): class RalphAPIViewSetMetaclass(type): def __new__(cls, name, bases, attrs): - attrs['_viewsets_registry'] = _viewsets_registry + attrs["_viewsets_registry"] = _viewsets_registry new_cls = super().__new__(cls, name, bases, attrs) - queryset = getattr(new_cls, 'queryset', None) + queryset = getattr(new_cls, "queryset", None) if queryset is not None: # don't evaluate queryset _viewsets_registry[queryset.model] = new_cls # filter_class should not be overwrited for RalphViewSet # use dedicated filter backend if you have specific needs - if 'filter_class' in attrs: - raise TypeError('Cannot define filter_class for RalphAPIViewSet') + if "filter_class" in attrs: + raise TypeError("Cannot define filter_class for RalphAPIViewSet") return new_cls class RalphAPIViewSet( - RalphAPIViewSetMixin, - viewsets.ModelViewSet, - metaclass=RalphAPIViewSetMetaclass + RalphAPIViewSetMixin, viewsets.ModelViewSet, metaclass=RalphAPIViewSetMetaclass ): pass @@ -155,6 +152,6 @@ class RalphAPIViewSet( class RalphReadOnlyAPIViewSet( RalphAPIViewSetMixin, viewsets.ReadOnlyModelViewSet, - metaclass=RalphAPIViewSetMetaclass + metaclass=RalphAPIViewSetMetaclass, ): pass diff --git a/src/ralph/apps.py b/src/ralph/apps.py index 5bd86834d7..67c7b55c1c 100644 --- a/src/ralph/apps.py +++ b/src/ralph/apps.py @@ -9,7 +9,7 @@ class RalphAppConfig(AppConfig): def get_load_modules_when_ready(self): - return ['subscribers', 'views'] + return ["subscribers", "views"] def ready(self): """ @@ -23,7 +23,7 @@ def ready(self): package = self.module.__name__ for module in self.get_load_modules_when_ready(): try: - import_module('{}.{}'.format(package, module)) + import_module("{}.{}".format(package, module)) except ImportError: pass diff --git a/src/ralph/assets/__init__.py b/src/ralph/assets/__init__.py index 6a2b4ff939..10508cac6a 100644 --- a/src/ralph/assets/__init__.py +++ b/src/ralph/assets/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.assets.apps.AssetsConfig' +default_app_config = "ralph.assets.apps.AssetsConfig" diff --git a/src/ralph/assets/_migration_helpers.py b/src/ralph/assets/_migration_helpers.py index c0f9b6c24f..db0419713c 100644 --- a/src/ralph/assets/_migration_helpers.py +++ b/src/ralph/assets/_migration_helpers.py @@ -22,22 +22,22 @@ def baseobject_migration( baseobject_ptr_id to point to new BaseObject id. At the end, update all related models to new point to new ids. """ - model_str = '{}.{}'.format(app_name, model_name) - logger.info('Inheriting {} from baseobject'.format(model_str)) + model_str = "{}.{}".format(app_name, model_name) + logger.info("Inheriting {} from baseobject".format(model_str)) Model = apps.get_model(app_name, model_name) - BaseObject = apps.get_model('assets', 'BaseObject') - ContentType = apps.get_model('contenttypes', 'ContentType') + BaseObject = apps.get_model("assets", "BaseObject") + ContentType = apps.get_model("contenttypes", "ContentType") model_content_type = ContentType.objects.get_for_model(Model) id_mapping = {} max_id = 0 - logger.info('Creating new IDs for {}'.format(model_str)) - for obj in Model._default_manager.order_by('baseobject_ptr_id'): + logger.info("Creating new IDs for {}".format(model_str)) + for obj in Model._default_manager.order_by("baseobject_ptr_id"): # first of all, create new BaseObject instance for each object # it's id will be later referenced as baseobject_ptr_id base_object = BaseObject.objects.create( content_type_id=model_content_type.id, - **{k: getattr(obj, v) for (k, v) in (rewrite_fields or {}).items()} + **{k: getattr(obj, v) for (k, v) in (rewrite_fields or {}).items()}, ) old_pk = obj.pk id_mapping[old_pk] = base_object.id @@ -45,10 +45,10 @@ def baseobject_migration( # increase ID of each object by Model._default_manager.update( - baseobject_ptr_id=models.F('baseobject_ptr_id') + max_id + baseobject_ptr_id=models.F("baseobject_ptr_id") + max_id ) - for obj in Model._default_manager.order_by('baseobject_ptr_id'): + for obj in Model._default_manager.order_by("baseobject_ptr_id"): # use update instead of model save to call it directly in SQL without # Django mediation (it will try to create new object instead of updating # the old one) @@ -56,9 +56,7 @@ def baseobject_migration( Model._default_manager.filter(baseobject_ptr_id=old_pk).update( baseobject_ptr_id=id_mapping[old_pk - max_id], ) - logger.info( - 'Mapping {} to {}'.format(old_pk, id_mapping[old_pk - max_id]) - ) + logger.info("Mapping {} to {}".format(old_pk, id_mapping[old_pk - max_id])) # save each obj once again to refresh content type etc for obj in Model._default_manager.all(): @@ -67,34 +65,35 @@ def baseobject_migration( # foreign keys # migrated from deprecated get_all_related_objects(local_only=True) for relation in Model._meta.get_fields(include_parents=False): - if (relation.one_to_many or relation.one_to_one) and \ - relation.auto_created and not relation.concrete: + if ( + (relation.one_to_many or relation.one_to_one) + and relation.auto_created + and not relation.concrete + ): related_model = relation.related_model relation_field = relation.field.attname - logger.info('Processing relation {}<->{} using field {}'.format( - model_str, related_model, relation_field - )) + logger.info( + "Processing relation {}<->{} using field {}".format( + model_str, related_model, relation_field + ) + ) relation_mapping = defaultdict(list) for related_object in related_model._default_manager.values_list( - 'pk', relation_field + "pk", relation_field ): relation_mapping[related_object[1]].append(related_object[0]) for old_id, new_id in id_mapping.items(): related_model._default_manager.filter( pk__in=relation_mapping.get(old_id, []) - ).update( - **{relation_field: new_id} - ) + ).update(**{relation_field: new_id}) # ImportedObjects - ImportedObjects = apps.get_model('data_importer', 'ImportedObjects') + ImportedObjects = apps.get_model("data_importer", "ImportedObjects") for old_id, new_id in id_mapping.items(): ImportedObjects._default_manager.filter( object_pk=old_id, content_type=model_content_type, - ).update( - object_pk=new_id - ) + ).update(object_pk=new_id) # TODO: m2m? @@ -102,17 +101,17 @@ def baseobject_migration( def _foreign_key_check_wrap(operations): db_engine = connection.vendor forward = reverse = None - if db_engine == 'mysql': - forward = 'SET foreign_key_checks=0;' - reverse = 'SET foreign_key_checks=1;' + if db_engine == "mysql": + forward = "SET foreign_key_checks=0;" + reverse = "SET foreign_key_checks=1;" # TODO: more engines if forward or reverse: - operations = [ - migrations.RunSQL(forward, reverse) - ] + operations + [ - migrations.RunSQL(reverse, forward) - ] + operations = ( + [migrations.RunSQL(forward, reverse)] + + operations + + [migrations.RunSQL(reverse, forward)] + ) return operations @@ -121,6 +120,7 @@ class DropAndCreateForeignKey(ContextDecorator): Drop FK to old_field before migration operation and recreate FK (to the new field) after migration operation. """ + def __init__(self, old_field, new_field, schema_editor): self.old_field = old_field self.new_field = new_field @@ -136,14 +136,10 @@ def __enter__(self): new_rel.related_model, [new_rel.field.column], foreign_key=True ) for fk_name in rel_fk_names: - logger.debug('Dropping FK to {} ({})'.format( - new_rel.field, fk_name - )) + logger.debug("Dropping FK to {} ({})".format(new_rel.field, fk_name)) self.schema_editor.execute( self.schema_editor._delete_constraint_sql( - self.schema_editor.sql_delete_fk, - new_rel.related_model, - fk_name + self.schema_editor.sql_delete_fk, new_rel.related_model, fk_name ) ) @@ -152,7 +148,7 @@ def __exit__(self, *exc): # (re)create any FK pointing to the new field for rel in self.new_field.model._meta.related_objects: if not rel.many_to_many: - logger.debug('Recreating FK to {}'.format(rel.field)) + logger.debug("Recreating FK to {}".format(rel.field)) self.schema_editor.execute( self.schema_editor._create_fk_sql( rel.related_model, rel.field, "_fk" @@ -176,9 +172,8 @@ class RenameFieldWithFKDrop(migrations.RenameField): http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html http://stackoverflow.com/questions/2014498/renaming-foreign-key-columns-in-mysql # noqa """ - def database_forwards( - self, app_label, schema_editor, from_state, to_state - ): + + def database_forwards(self, app_label, schema_editor, from_state, to_state): to_model = to_state.apps.get_model(app_label, self.model_name) if self.allow_migrate_model(schema_editor.connection.alias, to_model): from_model = from_state.apps.get_model(app_label, self.model_name) @@ -187,9 +182,7 @@ def database_forwards( with DropAndCreateForeignKey(old_field, new_field, schema_editor): schema_editor.alter_field(from_model, old_field, new_field) - def database_backwards( - self, app_label, schema_editor, from_state, to_state - ): + def database_backwards(self, app_label, schema_editor, from_state, to_state): to_model = to_state.apps.get_model(app_label, self.model_name) if self.allow_migrate_model(schema_editor.connection.alias, to_model): from_model = from_state.apps.get_model(app_label, self.model_name) @@ -203,9 +196,12 @@ class InheritFromBaseObject(migrations.SeparateDatabaseAndState): """ Handle migrating model to inherit from BaseObject. """ + def __init__(self, app_name, model_name, rewrite_fields=None): baseobject_model_migration = partial( - baseobject_migration, app_name=app_name, model_name=model_name, + baseobject_migration, + app_name=app_name, + model_name=model_name, rewrite_fields=rewrite_fields, ) @@ -219,18 +215,18 @@ def __init__(self, app_name, model_name, rewrite_fields=None): state_operations = [ migrations.RemoveField( model_name=model_name.lower(), - name='id', + name="id", ), migrations.AddField( model_name=model_name.lower(), - name='baseobject_ptr', + name="baseobject_ptr", field=models.OneToOneField( auto_created=True, - to='assets.BaseObject', + to="assets.BaseObject", serialize=False, primary_key=True, parent_link=True, - on_delete=models.CASCADE + on_delete=models.CASCADE, ), preserve_default=False, ), @@ -239,8 +235,8 @@ def __init__(self, app_name, model_name, rewrite_fields=None): database_operations = [ RenameFieldWithFKDrop( model_name=model_name.lower(), - old_name='id', - new_name='baseobject_ptr_id' + old_name="id", + new_name="baseobject_ptr_id", ), migrations.RunPython( baseobject_model_migration, @@ -251,5 +247,5 @@ def __init__(self, app_name, model_name, rewrite_fields=None): super().__init__( database_operations=_foreign_key_check_wrap(database_operations), - state_operations=state_operations + state_operations=state_operations, ) diff --git a/src/ralph/assets/admin.py b/src/ralph/assets/admin.py index ddabef29fb..f62fdbe629 100644 --- a/src/ralph/assets/admin.py +++ b/src/ralph/assets/admin.py @@ -19,7 +19,7 @@ ManufacturerKind, ProfitCenter, Service, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.models.base import BaseObject from ralph.assets.models.components import ( @@ -29,12 +29,9 @@ FibreChannelCard, GenericComponent, Memory, - Processor -) -from ralph.assets.models.configuration import ( - ConfigurationClass, - ConfigurationModule + Processor, ) +from ralph.assets.models.configuration import ConfigurationClass, ConfigurationModule from ralph.data_importer import resources from ralph.lib.custom_fields.admin import CustomFieldValueAdminMixin from ralph.lib.table.table import Table, TableWithUrl @@ -43,91 +40,83 @@ @register(ConfigurationClass) class ConfigurationClassAdmin(CustomFieldValueAdminMixin, RalphAdmin): - fields = ['class_name', 'module', 'path'] - readonly_fields = ['path'] - raw_id_fields = ['module'] + fields = ["class_name", "module", "path"] + readonly_fields = ["path"] + raw_id_fields = ["module"] search_fields = [ - 'path', + "path", ] - list_display = ['class_name', 'module', 'path', 'objects_count'] - list_select_related = ['module'] - list_filter = ['class_name', 'module'] + list_display = ["class_name", "module", "path", "objects_count"] + list_select_related = ["module"] + list_filter = ["class_name", "module"] show_custom_fields_values_summary = False def get_queryset(self, request): qs = super().get_queryset(request) - qs = qs.annotate(objects_count=Count('baseobject')) + qs = qs.annotate(objects_count=Count("baseobject")) return qs def objects_count(self, instance): return instance.objects_count - objects_count.short_description = _('Objects count') - objects_count.admin_order_field = 'objects_count' + + objects_count.short_description = _("Objects count") + objects_count.admin_order_field = "objects_count" def get_readonly_fields(self, request, obj=None): if obj: - return self.readonly_fields + ['class_name', 'module'] + return self.readonly_fields + ["class_name", "module"] return self.readonly_fields @register(ConfigurationModule) class ConfigurationModuleAdmin(CustomFieldValueAdminMixin, RalphMPTTAdmin): - list_display = ['name'] - search_fields = ['name'] - readonly_fields = [ - 'show_children_modules', 'show_children_classes' - ] - raw_id_fields = ['parent'] + list_display = ["name"] + search_fields = ["name"] + readonly_fields = ["show_children_modules", "show_children_classes"] + raw_id_fields = ["parent"] fieldsets = ( - (_('Basic info'), { - 'fields': [ - 'name', 'parent', 'support_team' - ] - }), - (_('Relations'), { - 'fields': [ - 'show_children_modules', 'show_children_classes' - ] - }) + (_("Basic info"), {"fields": ["name", "parent", "support_team"]}), + ( + _("Relations"), + {"fields": ["show_children_modules", "show_children_classes"]}, + ), ) show_custom_fields_values_summary = False @mark_safe def show_children_modules(self, module): if not module or not module.pk: - return '–' + return "–" return TableWithUrl( - module.children_modules.all(), - ['name'], - url_field='name' + module.children_modules.all(), ["name"], url_field="name" ).render() - show_children_modules.short_description = _('Children modules') + + show_children_modules.short_description = _("Children modules") @mark_safe def show_children_classes(self, module): if not module or not module.pk: - return '–' + return "–" return TableWithUrl( - module.configuration_classes.all(), - ['class_name'], - url_field='class_name' + module.configuration_classes.all(), ["class_name"], url_field="class_name" ).render() - show_children_classes.short_description = _('Children classes') + + show_children_classes.short_description = _("Children classes") def get_readonly_fields(self, request, obj=None): if obj: - return self.readonly_fields + ['name', 'parent'] + return self.readonly_fields + ["name", "parent"] return self.readonly_fields @register(ServiceEnvironment) class ServiceEnvironmentAdmin(CustomFieldValueAdminMixin, RalphAdmin): show_custom_fields_values_summary = False - search_fields = ['service__name', 'environment__name'] - list_select_related = ['service', 'environment'] - raw_id_fields = ['service', 'environment'] + search_fields = ["service__name", "environment__name"] + list_select_related = ["service", "environment"] + raw_id_fields = ["service", "environment"] resource_class = resources.ServiceEnvironmentResource - fields = ('service', 'environment', 'remarks', 'tags') + fields = ("service", "environment", "remarks", "tags") class PolymorphicInlineFormset(BaseInlineFormSet): @@ -137,87 +126,94 @@ def get_queryset(self): class ServiceEnvironmentInline(RalphTabularInline): model = ServiceEnvironment - raw_id_fields = ['environment'] - fields = ('environment',) + raw_id_fields = ["environment"] + fields = ("environment",) min_num = 1 formset = PolymorphicInlineFormset class BaseObjectsList(ScanStatusInTableMixin, Table): def url(self, item): - return '
    {}'.format( - item.get_absolute_url(), - _('Go to object') - ) - url.title = _('Link') + return '{}'.format(item.get_absolute_url(), _("Go to object")) + + url.title = _("Link") def _str(self, item): return str(item) - _str.title = _('object') + + _str.title = _("object") class ServiceBaseObjects(RalphDetailView): - icon = 'bookmark' - name = 'service_base_objects' - label = _('Objects') - url_name = 'service_base_objects' + icon = "bookmark" + name = "service_base_objects" + label = _("Objects") + url_name = "service_base_objects" def get_service_base_objects_queryset(self): return BaseObject.polymorphic_objects.filter( service_env__service=self.object - ).select_related( - 'service_env__environment', 'content_type', 'securityscan' - ) + ).select_related("service_env__environment", "content_type", "securityscan") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['base_objects_list'] = BaseObjectsList( + context["base_objects_list"] = BaseObjectsList( self.get_service_base_objects_queryset(), [ - 'id', ('content_type', _('type')), - ('service_env__environment', _('environment')), '_str', - 'scan_status', 'url', - ] + "id", + ("content_type", _("type")), + ("service_env__environment", _("environment")), + "_str", + "scan_status", + "url", + ], ) return context def get_object(self, model, pk): if pk.isdigit(): - query = {'pk': pk} + query = {"pk": pk} else: - query = {'uid': pk} + query = {"uid": pk} return model.objects.get(**query) @classmethod def get_url_pattern(cls, model): - return r'^{}/{}/(?P[\w-]+)/{}/$'.format( + return r"^{}/{}/(?P[\w-]+)/{}/$".format( model._meta.app_label, model._meta.model_name, cls.url_name ) @register(ManufacturerKind) class ManufacturerKindAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(Service) class ServiceAdmin(RalphAdmin): - list_display = ['name', 'uid', 'active', 'business_segment'] - search_fields = ['name', 'uid'] - list_filter = [ - 'active', 'business_segment', 'profit_center', 'support_team' - ] - list_select_related = ['business_segment'] + list_display = ["name", "uid", "active", "business_segment"] + search_fields = ["name", "uid"] + list_filter = ["active", "business_segment", "profit_center", "support_team"] + list_select_related = ["business_segment"] fields = ( - 'name', 'uid', 'active', 'profit_center', 'business_segment', - 'cost_center', 'technical_owners', 'business_owners', 'support_team', + "name", + "uid", + "active", + "profit_center", + "business_segment", + "cost_center", + "technical_owners", + "business_owners", + "support_team", ) inlines = [ServiceEnvironmentInline] raw_id_fields = [ - 'profit_center', 'support_team', 'business_owners', 'technical_owners' + "profit_center", + "support_team", + "business_owners", + "technical_owners", ] resource_class = resources.ServiceResource change_views = [ServiceBaseObjects] @@ -225,79 +221,80 @@ class ServiceAdmin(RalphAdmin): @register(Manufacturer) class ManufacturerAdmin(RalphAdmin): - - search_fields = ['name', ] + search_fields = [ + "name", + ] list_filter = [ - 'manufacturer_kind', + "manufacturer_kind", ] @register(BudgetInfo) class BudgetInfoAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(Environment) class EnvironmentAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(BusinessSegment) class BusinessSegmentAdmin(RalphAdmin): - - search_fields = ['name'] - list_display = ['name', 'services_count'] + search_fields = ["name"] + list_display = ["name", "services_count"] def get_queryset(self, request): - return BusinessSegment.objects.annotate(services_count=Count('service')) + return BusinessSegment.objects.annotate(services_count=Count("service")) def services_count(self, instance): return instance.services_count - services_count.short_description = _('Services count') - services_count.admin_order_field = 'services_count' + + services_count.short_description = _("Services count") + services_count.admin_order_field = "services_count" @register(ProfitCenter) class ProfitCenterAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(AssetModel) -class AssetModelAdmin( - CustomFieldValueAdminMixin, - RalphAdmin -): - +class AssetModelAdmin(CustomFieldValueAdminMixin, RalphAdmin): resource_class = resources.AssetModelResource - list_select_related = ['manufacturer', 'category'] - list_display = ['name', 'type', 'manufacturer', 'category', 'assets_count'] - raw_id_fields = ['manufacturer'] - search_fields = ['name', 'manufacturer__name'] - list_filter = ['type', 'manufacturer', 'category'] - ordering = ['name'] + list_select_related = ["manufacturer", "category"] + list_display = ["name", "type", "manufacturer", "category", "assets_count"] + raw_id_fields = ["manufacturer"] + search_fields = ["name", "manufacturer__name"] + list_filter = ["type", "manufacturer", "category"] + ordering = ["name"] fields = ( - 'name', 'manufacturer', 'category', 'type', 'has_parent', - 'cores_count', 'height_of_device', 'power_consumption', - 'visualization_layout_front', 'visualization_layout_back' + "name", + "manufacturer", + "category", + "type", + "has_parent", + "cores_count", + "height_of_device", + "power_consumption", + "visualization_layout_front", + "visualization_layout_back", ) def get_queryset(self, request): - return AssetModel.objects.annotate(assets_count=Count('assets')) + return AssetModel.objects.annotate(assets_count=Count("assets")) def assets_count(self, instance): return instance.assets_count - assets_count.short_description = _('Assets count') - assets_count.admin_order_field = 'assets_count' + + assets_count.short_description = _("Assets count") + assets_count.admin_order_field = "assets_count" @register(Category) class CategoryAdmin(RalphMPTTAdmin): - - search_fields = ['name'] - list_display = ['name', 'code'] + search_fields = ["name"] + list_display = ["name", "code"] resource_class = resources.CategoryResource def get_actions(self, request): @@ -305,22 +302,22 @@ def get_actions(self, request): class ComponentAdminMixin(object): - raw_id_fields = ['base_object', 'model'] + raw_id_fields = ["base_object", "model"] @register(ComponentModel) class ComponentModelAdmin(RalphAdmin): - search_fields = ['name'] + search_fields = ["name"] @register(GenericComponent) class GenericComponentAdmin(ComponentAdminMixin, RalphAdmin): - search_fields = ['name'] + search_fields = ["name"] @register(Ethernet) class EthernetAdmin(ComponentAdminMixin, RalphAdmin): - search_fields = ['label', 'mac'] + search_fields = ["label", "mac"] @register(Disk, FibreChannelCard, Memory, Processor) @@ -330,19 +327,19 @@ class ComponentAdmin(ComponentAdminMixin, RalphAdmin): @register(Asset) class AssetAdmin(RalphAdmin): - raw_id_fields = ['parent', 'service_env', 'model'] - search_fields = ['hostname', 'sn', 'barcode'] + raw_id_fields = ["parent", "service_env", "model"] + search_fields = ["hostname", "sn", "barcode"] @register(BaseObject) class BaseObjectAdmin(RalphAdmin): - list_display = ['repr'] - raw_id_fields = ['parent', 'service_env'] - exclude = ('content_type',) - list_select_related = ['content_type'] + list_display = ["repr"] + raw_id_fields = ["parent", "service_env"] + exclude = ("content_type",) + list_select_related = ["content_type"] def repr(self, obj): - return '{}: {}'.format(obj.content_type, obj) + return "{}: {}".format(obj.content_type, obj) def has_add_permission(self, request): return False @@ -350,5 +347,4 @@ def has_add_permission(self, request): @register(AssetHolder) class AssetHolderAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] diff --git a/src/ralph/assets/api/filters.py b/src/ralph/assets/api/filters.py index 0c4101a810..3da5876ea8 100644 --- a/src/ralph/assets/api/filters.py +++ b/src/ralph/assets/api/filters.py @@ -5,12 +5,13 @@ class NetworkableObjectFilters(django_filters.FilterSet): """ Base filter for all networkable objects for example with IP address. """ + configuration_path = django_filters.CharFilter( - field_name='configuration_path__path' + field_name="configuration_path__path" ) - ip = django_filters.CharFilter(field_name='ethernet_set__ipaddress__address') + ip = django_filters.CharFilter(field_name="ethernet_set__ipaddress__address") class Meta: fields = [ - 'configuration_path__module__name', + "configuration_path__module__name", ] diff --git a/src/ralph/assets/api/routers.py b/src/ralph/assets/api/routers.py index 19cb3a2aa2..363a80a4b7 100644 --- a/src/ralph/assets/api/routers.py +++ b/src/ralph/assets/api/routers.py @@ -19,28 +19,28 @@ ProcessorViewSet, ProfitCenterViewSet, ServiceEnvironmentViewSet, - ServiceViewSet + ServiceViewSet, ) -router.register(r'assetholders', AssetHolderViewSet) -router.register(r'assetmodels', AssetModelViewSet) -router.register(r'budget-info', BudgetInfoViewSet) -router.register(r'base-objects', BaseObjectViewSet) -router.register(r'business-segments', BusinessSegmentViewSet) -router.register(r'categories', CategoryViewSet) -router.register(r'configuration-modules', ConfigurationModuleViewSet) -router.register(r'configuration-classes', ConfigurationClassViewSet) -router.register(r'disks', DiskViewSet) -router.register(r'environments', EnvironmentViewSet) -router.register(r'fibre-channel-cards', FibreChannelCardViewSet) -router.register(r'ethernets', EthernetViewSet) -router.register(r'memory', MemoryViewSet) -router.register(r'manufacturers', ManufacturerViewSet) -router.register(r'manufacturer-kind', ManufacturerKindViewSet) -router.register(r'processors', ProcessorViewSet) -router.register(r'profit-centers', ProfitCenterViewSet) -router.register(r'services-environments', ServiceEnvironmentViewSet) -router.register(r'services', ServiceViewSet) -router.register(r'dc-hosts', DCHostViewSet, base_name='dchost') +router.register(r"assetholders", AssetHolderViewSet) +router.register(r"assetmodels", AssetModelViewSet) +router.register(r"budget-info", BudgetInfoViewSet) +router.register(r"base-objects", BaseObjectViewSet) +router.register(r"business-segments", BusinessSegmentViewSet) +router.register(r"categories", CategoryViewSet) +router.register(r"configuration-modules", ConfigurationModuleViewSet) +router.register(r"configuration-classes", ConfigurationClassViewSet) +router.register(r"disks", DiskViewSet) +router.register(r"environments", EnvironmentViewSet) +router.register(r"fibre-channel-cards", FibreChannelCardViewSet) +router.register(r"ethernets", EthernetViewSet) +router.register(r"memory", MemoryViewSet) +router.register(r"manufacturers", ManufacturerViewSet) +router.register(r"manufacturer-kind", ManufacturerKindViewSet) +router.register(r"processors", ProcessorViewSet) +router.register(r"profit-centers", ProfitCenterViewSet) +router.register(r"services-environments", ServiceEnvironmentViewSet) +router.register(r"services", ServiceViewSet) +router.register(r"dc-hosts", DCHostViewSet, basename="dchost") urlpatterns = [] diff --git a/src/ralph/assets/api/serializers.py b/src/ralph/assets/api/serializers.py index 580c288bb4..9b5d9429d4 100644 --- a/src/ralph/assets/api/serializers.py +++ b/src/ralph/assets/api/serializers.py @@ -9,7 +9,7 @@ from ralph.api.serializers import ( AdditionalLookupRelatedField, RalphAPISaveSerializer, - ReversionHistoryAPISerializerMixin + ReversionHistoryAPISerializerMixin, ) from ralph.api.utils import PolymorphicSerializer from ralph.assets.models import ( @@ -27,14 +27,14 @@ ManufacturerKind, ProfitCenter, Service, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.models.components import ( Disk, Ethernet, FibreChannelCard, Memory, - Processor + Processor, ) from ralph.configuration_management.api import SCMInfoSerializer from ralph.lib.custom_fields.api import WithCustomFieldsSerializerMixin @@ -52,9 +52,11 @@ def get_object_type(self, instance): class OwnersFromServiceEnvSerializerMixin(RalphAPISerializer): business_owners = SimpleRalphUserSerializer( - many=True, source='service_env.service.business_owners', required=False) + many=True, source="service_env.service.business_owners", required=False + ) technical_owners = SimpleRalphUserSerializer( - many=True, source='service_env.service.technical_owners', required=False) + many=True, source="service_env.service.technical_owners", required=False + ) class BusinessSegmentSerializer(RalphAPISerializer): @@ -72,7 +74,7 @@ class Meta: class ProfitCenterSerializer(RalphAPISerializer): class Meta: model = ProfitCenter - fields = ('id', 'name', 'description', 'url') + fields = ("id", "name", "description", "url") depth = 1 @@ -82,10 +84,7 @@ class Meta: fields = "__all__" -class SaveServiceSerializer( - ReversionHistoryAPISerializerMixin, - RalphAPISerializer -): +class SaveServiceSerializer(ReversionHistoryAPISerializerMixin, RalphAPISerializer): """ Serializer to save (create or update) services. Environments should be passed as a list of ids. @@ -94,25 +93,40 @@ class SaveServiceSerializer( (ex. `ServiceEnvironment`). We're overwriting save mechanism to handle this m2m relationship ourself. """ + environments = AdditionalLookupRelatedField( - many=True, read_only=False, queryset=Environment.objects.all(), - lookup_fields=['name'], + many=True, + read_only=False, + queryset=Environment.objects.all(), + lookup_fields=["name"], ) business_owners = AdditionalLookupRelatedField( - many=True, read_only=False, queryset=get_user_model().objects.all(), - lookup_fields=['username'], style={'base_template': 'input.html'} + many=True, + read_only=False, + queryset=get_user_model().objects.all(), + lookup_fields=["username"], + style={"base_template": "input.html"}, ) technical_owners = AdditionalLookupRelatedField( - many=True, read_only=False, queryset=get_user_model().objects.all(), - lookup_fields=['username'], style={'base_template': 'input.html'} + many=True, + read_only=False, + queryset=get_user_model().objects.all(), + lookup_fields=["username"], + style={"base_template": "input.html"}, ) support_team = AdditionalLookupRelatedField( - read_only=False, queryset=Team.objects.all(), lookup_fields=['name'], - required=False, allow_null=True, + read_only=False, + queryset=Team.objects.all(), + lookup_fields=["name"], + required=False, + allow_null=True, ) profit_center = AdditionalLookupRelatedField( - read_only=False, queryset=ProfitCenter.objects.all(), - lookup_fields=['name'], required=False, allow_null=True, + read_only=False, + queryset=ProfitCenter.objects.all(), + lookup_fields=["name"], + required=False, + allow_null=True, ) class Meta: @@ -129,10 +143,8 @@ def _save_environments(self, instance, environments): environment__in=environments ).delete() current_environments = set( - ServiceEnvironment.objects.filter( - service=instance - ).values_list( - 'environment_id', flat=True + ServiceEnvironment.objects.filter(service=instance).values_list( + "environment_id", flat=True ) ) # create ServiceEnv for new environments @@ -143,13 +155,13 @@ def _save_environments(self, instance, environments): ) def create(self, validated_data): - environments = validated_data.pop('environments', []) + environments = validated_data.pop("environments", []) instance = super().create(validated_data) self._save_environments(instance, environments) return instance def update(self, instance, validated_data): - environments = validated_data.pop('environments', None) + environments = validated_data.pop("environments", None) result = super().update(instance, validated_data) if environments is not None: self._save_environments(instance, environments) @@ -157,7 +169,6 @@ def update(self, instance, validated_data): class ServiceSerializer(RalphAPISerializer): - business_owners = SimpleRalphUserSerializer(many=True) technical_owners = SimpleRalphUserSerializer(many=True) @@ -168,16 +179,18 @@ class Meta: class ServiceEnvironmentSimpleSerializer(RalphAPISerializer): - service = serializers.CharField(source='service_name', read_only=True) - environment = serializers.CharField( - source='environment_name', read_only=True - ) + service = serializers.CharField(source="service_name", read_only=True) + environment = serializers.CharField(source="environment_name", read_only=True) service_uid = serializers.CharField(read_only=True) class Meta: model = ServiceEnvironment fields = ( - 'id', 'service', 'environment', 'url', 'service_uid', + "id", + "service", + "environment", + "url", + "service_uid", ) _skip_tags_field = True @@ -185,20 +198,20 @@ class Meta: class ServiceEnvironmentSerializer( TypeFromContentTypeSerializerMixin, WithCustomFieldsSerializerMixin, - RalphAPISerializer + RalphAPISerializer, ): __str__ = StrField(show_type=True) business_owners = SimpleRalphUserSerializer( - many=True, source='service.business_owners' + many=True, source="service.business_owners" ) technical_owners = SimpleRalphUserSerializer( - many=True, source='service.technical_owners' + many=True, source="service.technical_owners" ) class Meta: model = ServiceEnvironment depth = 1 - exclude = ('content_type', 'parent', 'service_env') + exclude = ("content_type", "parent", "service_env") class ManufacturerSerializer(RalphAPISerializer): @@ -214,10 +227,7 @@ class Meta: class CategorySerializer(RalphAPISerializer): - - depreciation_rate = serializers.FloatField( - source='get_default_depreciation_rate' - ) + depreciation_rate = serializers.FloatField(source="get_default_depreciation_rate") class Meta: model = Category @@ -225,44 +235,52 @@ class Meta: class AssetModelSerializer(WithCustomFieldsSerializerMixin, RalphAPISerializer): - category = CategorySerializer() class Meta: model = AssetModel fields = ( - 'id', 'url', 'custom_fields', 'configuration_variables', - 'category', 'name', 'created', 'modified', 'type', - 'power_consumption', 'height_of_device', 'cores_count', - 'visualization_layout_front', 'visualization_layout_back', - 'has_parent', 'manufacturer', + "id", + "url", + "custom_fields", + "configuration_variables", + "category", + "name", + "created", + "modified", + "type", + "power_consumption", + "height_of_device", + "cores_count", + "visualization_layout_front", + "visualization_layout_back", + "has_parent", + "manufacturer", ) depth = 1 class AssetModelSaveSerializer(RalphAPISaveSerializer): - class Meta: model = AssetModel fields = "__all__" class BaseObjectPolymorphicSerializer( - TypeFromContentTypeSerializerMixin, - PolymorphicSerializer, - RalphAPISerializer + TypeFromContentTypeSerializerMixin, PolymorphicSerializer, RalphAPISerializer ): """ Serializer for BaseObjects viewset (serialize each model using dedicated serializer). """ + __str__ = StrField(show_type=True) service_env = ServiceEnvironmentSerializer() scmstatuscheck = SCMInfoSerializer() class Meta: model = BaseObject - exclude = ('content_type',) + exclude = ("content_type",) class AssetHolderSerializer(RalphAPISerializer): @@ -274,27 +292,26 @@ class Meta: class BaseObjectSimpleSerializer( TypeFromContentTypeSerializerMixin, WithCustomFieldsSerializerMixin, - RalphAPISerializer + RalphAPISerializer, ): __str__ = StrField(show_type=True) class Meta: model = BaseObject - exclude = ('content_type', ) + exclude = ("content_type",) class ConfigurationModuleSimpleSerializer(RalphAPISerializer): class Meta: model = ConfigurationModule - fields = ('id', 'url', 'name', 'parent', 'support_team') + fields = ("id", "url", "name", "parent", "support_team") class ConfigurationModuleSerializer( - WithCustomFieldsSerializerMixin, - ConfigurationModuleSimpleSerializer + WithCustomFieldsSerializerMixin, ConfigurationModuleSimpleSerializer ): children_modules = serializers.HyperlinkedRelatedField( - view_name='configurationmodule-detail', + view_name="configurationmodule-detail", many=True, read_only=True, required=False, @@ -302,7 +319,8 @@ class ConfigurationModuleSerializer( class Meta(ConfigurationModuleSimpleSerializer.Meta): fields = ConfigurationModuleSimpleSerializer.Meta.fields + ( - 'children_modules', 'custom_fields' + "children_modules", + "custom_fields", ) @@ -311,33 +329,31 @@ class ConfigurationClassSimpleSerializer(RalphAPISerializer): class Meta: model = ConfigurationClass - exclude = ( - 'content_type', 'configuration_path', - 'parent' - ) + exclude = ("content_type", "configuration_path", "parent") # TODO: Is there a better way to make it work since drf 3.5? -del ConfigurationClassSimpleSerializer._declared_fields['tags'] +del ConfigurationClassSimpleSerializer._declared_fields["tags"] class ConfigurationClassSerializer( TypeFromContentTypeSerializerMixin, WithCustomFieldsSerializerMixin, - RalphAPISerializer + RalphAPISerializer, ): __str__ = StrField(show_type=True) module = ConfigurationModuleSimpleSerializer() class Meta: model = ConfigurationClass - exclude = ('content_type', 'service_env', 'configuration_path') + exclude = ("content_type", "service_env", "configuration_path") class BaseObjectSerializer(BaseObjectSimpleSerializer): """ Base class for other serializers inheriting from `BaseObject`. """ + service_env = ServiceEnvironmentSimpleSerializer() licences = SimpleBaseObjectLicenceSerializer(read_only=True, many=True) configuration_path = ConfigurationClassSimpleSerializer() @@ -356,11 +372,10 @@ class EthernetSimpleSerializer(RalphAPISerializer): class Meta: model = Ethernet - fields = ('id', 'mac', 'ipaddress', 'url') + fields = ("id", "mac", "ipaddress", "url") class EthernetSerializer(EthernetSimpleSerializer): - class Meta: model = Ethernet depth = 1 @@ -370,47 +385,52 @@ class Meta: class MemorySimpleSerializer(RalphAPISerializer): class Meta: model = Memory - fields = ('id', 'url', 'size', 'speed') + fields = ("id", "url", "size", "speed") class MemorySerializer(MemorySimpleSerializer): class Meta: depth = 1 model = Memory - exclude = ('model',) + exclude = ("model",) class FibreChannelCardSimpleSerializer(RalphAPISerializer): class Meta: model = FibreChannelCard - fields = ('id', 'url', 'firmware_version', 'speed', 'wwn') + fields = ("id", "url", "firmware_version", "speed", "wwn") class FibreChannelCardSerializer(FibreChannelCardSimpleSerializer): class Meta: depth = 1 model = FibreChannelCard - exclude = ('model',) + exclude = ("model",) class ProcessorSimpleSerializer(RalphAPISerializer): class Meta: model = Processor - fields = ('id', 'url', 'speed', 'cores', 'logical_cores') + fields = ("id", "url", "speed", "cores", "logical_cores") class ProcessorSerializer(ProcessorSimpleSerializer): class Meta: depth = 1 model = Processor - exclude = ('model',) + exclude = ("model",) class DiskSimpleSerializer(RalphAPISerializer): class Meta: model = Disk fields = ( - 'id', 'url', 'size', 'serial_number', 'slot', 'firmware_version', + "id", + "url", + "size", + "serial_number", + "slot", + "firmware_version", ) @@ -418,13 +438,13 @@ class DiskSerializer(DiskSimpleSerializer): class Meta: depth = 1 model = Disk - exclude = ('model',) + exclude = ("model",) # used by DataCenterAsset and VirtualServer serializers class NetworkComponentSerializerMixin(OwnersFromServiceEnvSerializerMixin): # TODO(xor-xor): ethernet -> ethernets - ethernet = EthernetSimpleSerializer(many=True, source='ethernet_set') + ethernet = EthernetSimpleSerializer(many=True, source="ethernet_set") ipaddresses = fields.SerializerMethodField() def get_ipaddresses(self, instance): @@ -447,13 +467,12 @@ def get_ipaddresses(self, instance): # used by DataCenterAsset and VirtualServer serializers class ComponentSerializerMixin(NetworkComponentSerializerMixin): - disk = DiskSimpleSerializer(many=True, source='disk_set') - memory = MemorySimpleSerializer(many=True, source='memory_set') - processors = ProcessorSimpleSerializer(many=True, source='processor_set') + disk = DiskSimpleSerializer(many=True, source="disk_set") + memory = MemorySimpleSerializer(many=True, source="memory_set") + processors = ProcessorSimpleSerializer(many=True, source="processor_set") class SecurityScanField(serializers.Field): - def to_representation(self, value): if value and value.pk: return SecurityScanSerializer().to_representation(value) diff --git a/src/ralph/assets/api/serializers_dchosts.py b/src/ralph/assets/api/serializers_dchosts.py index 3b0c00d9a4..70636c5ff3 100644 --- a/src/ralph/assets/api/serializers_dchosts.py +++ b/src/ralph/assets/api/serializers_dchosts.py @@ -3,7 +3,7 @@ from ralph.assets.api.serializers import ( BaseObjectSerializer, ComponentSerializerMixin, - SecurityScanField + SecurityScanField, ) from ralph.assets.models import BaseObject from ralph.data_center.api.serializers import DataCenterAssetSimpleSerializer @@ -18,19 +18,24 @@ class DCHostSerializer(ComponentSerializerMixin, BaseObjectSerializer): class Meta: model = DCHost fields = [ - 'id', - 'url', - 'ethernet', - 'ipaddresses', - 'custom_fields', - 'tags', - 'securityscan', - 'object_type', - '__str__', - 'service_env', 'configuration_path', - 'hostname', - 'created', 'modified', 'remarks', 'parent', - 'configuration_variables', 'hypervisor' + "id", + "url", + "ethernet", + "ipaddresses", + "custom_fields", + "tags", + "securityscan", + "object_type", + "__str__", + "service_env", + "configuration_path", + "hostname", + "created", + "modified", + "remarks", + "parent", + "configuration_variables", + "hypervisor", ] @@ -39,7 +44,7 @@ class DCHostPhysicalSerializer(DCHostSerializer): class Meta: model = BaseObject - fields = DCHostSerializer.Meta.fields + ['model'] + fields = DCHostSerializer.Meta.fields + ["model"] def get_model(self, obj): try: diff --git a/src/ralph/assets/api/views.py b/src/ralph/assets/api/views.py index 7fd492dfd4..31cffdc0c2 100644 --- a/src/ralph/assets/api/views.py +++ b/src/ralph/assets/api/views.py @@ -259,9 +259,7 @@ class Meta(NetworkableObjectFilters.Meta): # TODO: move to data_center and use DCHost proxy model class DCHostViewSet(BaseObjectViewSetMixin, RalphAPIViewSet): - queryset = ( - BaseObject.polymorphic_objects - ) + queryset = BaseObject.polymorphic_objects serializer_class = ralph.assets.api.serializers_dchosts.DCHostSerializer renderer_classes = renderer_classes_without_form(RalphAPIViewSet.renderer_classes) http_method_names = ["get", "options", "head", "patch", "post"] @@ -308,19 +306,27 @@ def get_serializer_class(self, *args, **kwargs): obj_ = self.get_object() if isinstance(obj_, VirtualServer): from ralph.virtual.api import VirtualServerSaveSerializer + return VirtualServerSaveSerializer elif isinstance(obj_, DataCenterAsset): - from ralph.data_center.api.serializers import DataCenterAssetSaveSerializer + from ralph.data_center.api.serializers import ( + DataCenterAssetSaveSerializer, + ) + return DataCenterAssetSaveSerializer elif isinstance(obj_, CloudHost): from ralph.virtual.api import SaveCloudHostSerializer + return SaveCloudHostSerializer elif isinstance(obj_, Cluster): from ralph.data_center.api.serializers import ClusterSerializer + return ClusterSerializer else: raise NotFound() - except AssertionError: # for some reason when opening browsable api this raises + except ( + AssertionError + ): # for some reason when opening browsable api this raises pass return ralph.assets.api.serializers_dchosts.DCHostSerializer @@ -328,7 +334,7 @@ def get_queryset(self): return ( self.queryset.dc_hosts() .select_related(*self.select_related) - .polymorphic_select_related(Cluster=['type'], CloudHost=['hypervisor']) + .polymorphic_select_related(Cluster=["type"], CloudHost=["hypervisor"]) .polymorphic_prefetch_related( Cluster=[*self.prefetch_related], DataCenterAsset=[*self.prefetch_related], diff --git a/src/ralph/assets/apps.py b/src/ralph/assets/apps.py index 234c8657c2..45bf343b42 100644 --- a/src/ralph/assets/apps.py +++ b/src/ralph/assets/apps.py @@ -3,11 +3,10 @@ class AssetsConfig(RalphAppConfig): - - name = 'ralph.assets' + name = "ralph.assets" def get_load_modules_when_ready(self): - modules = ['signals'] + modules = ["signals"] if settings.ENABLE_HERMES_INTEGRATION: - modules.append('subscribers') + modules.append("subscribers") return modules diff --git a/src/ralph/assets/country_utils.py b/src/ralph/assets/country_utils.py index 5ed677268a..2afc52c0e5 100644 --- a/src/ralph/assets/country_utils.py +++ b/src/ralph/assets/country_utils.py @@ -1,56 +1,255 @@ # -*- coding: utf-8 -*- ISO_3166 = ( - ('AF', 'AFG'), ('AX', 'ALA'), ('AL', 'ALB'), ('DZ', 'DZA'), ('AS', 'ASM'), - ('AD', 'AND'), ('AO', 'AGO'), ('AI', 'AIA'), ('AQ', 'ATA'), ('AG', 'ATG'), - ('AR', 'ARG'), ('AM', 'ARM'), ('AW', 'ABW'), ('AU', 'AUS'), ('AT', 'AUT'), - ('AZ', 'AZE'), ('BS', 'BHS'), ('BH', 'BHR'), ('BD', 'BGD'), ('BB', 'BRB'), - ('BY', 'BLR'), ('BE', 'BEL'), ('BZ', 'BLZ'), ('BJ', 'BEN'), ('BM', 'BMU'), - ('BT', 'BTN'), ('BO', 'BOL'), ('BQ', 'BES'), ('BA', 'BIH'), ('BW', 'BWA'), - ('BV', 'BVT'), ('BR', 'BRA'), ('IO', 'IOT'), ('BN', 'BRN'), ('BG', 'BGR'), - ('BF', 'BFA'), ('BI', 'BDI'), ('KH', 'KHM'), ('CM', 'CMR'), ('CA', 'CAN'), - ('CV', 'CPV'), ('KY', 'CYM'), ('CF', 'CAF'), ('TD', 'TCD'), ('CL', 'CHL'), - ('CN', 'CHN'), ('CX', 'CXR'), ('CC', 'CCK'), ('CO', 'COL'), ('KM', 'COM'), - ('CG', 'COG'), ('CD', 'COD'), ('CK', 'COK'), ('CR', 'CRI'), ('CI', 'CIV'), - ('HR', 'HRV'), ('CU', 'CUB'), ('CW', 'CUW'), ('CY', 'CYP'), ('CZ', 'CZE'), - ('DK', 'DNK'), ('DJ', 'DJI'), ('DM', 'DMA'), ('DO', 'DOM'), ('EC', 'ECU'), - ('EG', 'EGY'), ('SV', 'SLV'), ('GQ', 'GNQ'), ('ER', 'ERI'), ('EE', 'EST'), - ('ET', 'ETH'), ('FK', 'FLK'), ('FO', 'FRO'), ('FJ', 'FJI'), ('FI', 'FIN'), - ('FR', 'FRA'), ('GF', 'GUF'), ('PF', 'PYF'), ('TF', 'ATF'), ('GA', 'GAB'), - ('GM', 'GMB'), ('GE', 'GEO'), ('DE', 'DEU'), ('GH', 'GHA'), ('GI', 'GIB'), - ('GR', 'GRC'), ('GL', 'GRL'), ('GD', 'GRD'), ('GP', 'GLP'), ('GU', 'GUM'), - ('GT', 'GTM'), ('GG', 'GGY'), ('GN', 'GIN'), ('GW', 'GNB'), ('GY', 'GUY'), - ('HT', 'HTI'), ('HM', 'HMD'), ('VA', 'VAT'), ('HN', 'HND'), ('HK', 'HKG'), - ('HU', 'HUN'), ('IS', 'ISL'), ('IN', 'IND'), ('ID', 'IDN'), ('IR', 'IRN'), - ('IQ', 'IRQ'), ('IE', 'IRL'), ('IM', 'IMN'), ('IL', 'ISR'), ('IT', 'ITA'), - ('JM', 'JAM'), ('JP', 'JPN'), ('JE', 'JEY'), ('JO', 'JOR'), ('KZ', 'KAZ'), - ('KE', 'KEN'), ('KI', 'KIR'), ('KP', 'PRK'), ('KR', 'KOR'), ('KW', 'KWT'), - ('KG', 'KGZ'), ('LA', 'LAO'), ('LV', 'LVA'), ('LB', 'LBN'), ('LS', 'LSO'), - ('LR', 'LBR'), ('LY', 'LBY'), ('LI', 'LIE'), ('LT', 'LTU'), ('LU', 'LUX'), - ('MO', 'MAC'), ('MK', 'MKD'), ('MG', 'MDG'), ('MW', 'MWI'), ('MY', 'MYS'), - ('MV', 'MDV'), ('ML', 'MLI'), ('MT', 'MLT'), ('MH', 'MHL'), ('MQ', 'MTQ'), - ('MR', 'MRT'), ('MU', 'MUS'), ('YT', 'MYT'), ('MX', 'MEX'), ('FM', 'FSM'), - ('MD', 'MDA'), ('MC', 'MCO'), ('MN', 'MNG'), ('ME', 'MNE'), ('MS', 'MSR'), - ('MA', 'MAR'), ('MZ', 'MOZ'), ('MM', 'MMR'), ('NA', 'NAM'), ('NR', 'NRU'), - ('NP', 'NPL'), ('NL', 'NLD'), ('NC', 'NCL'), ('NZ', 'NZL'), ('NI', 'NIC'), - ('NE', 'NER'), ('NG', 'NGA'), ('NU', 'NIU'), ('NF', 'NFK'), ('MP', 'MNP'), - ('NO', 'NOR'), ('OM', 'OMN'), ('PK', 'PAK'), ('PW', 'PLW'), ('PS', 'PSE'), - ('PA', 'PAN'), ('PG', 'PNG'), ('PY', 'PRY'), ('PE', 'PER'), ('PH', 'PHL'), - ('PN', 'PCN'), ('PL', 'POL'), ('PT', 'PRT'), ('PR', 'PRI'), ('QA', 'QAT'), - ('RE', 'REU'), ('RO', 'ROU'), ('RU', 'RUS'), ('RW', 'RWA'), ('BL', 'BLM'), - ('SH', 'SHN'), ('KN', 'KNA'), ('LC', 'LCA'), ('MF', 'MAF'), ('PM', 'SPM'), - ('VC', 'VCT'), ('WS', 'WSM'), ('SM', 'SMR'), ('ST', 'STP'), ('SA', 'SAU'), - ('SN', 'SEN'), ('RS', 'SRB'), ('SC', 'SYC'), ('SL', 'SLE'), ('SG', 'SGP'), - ('SX', 'SXM'), ('SK', 'SVK'), ('SI', 'SVN'), ('SB', 'SLB'), ('SO', 'SOM'), - ('ZA', 'ZAF'), ('GS', 'SGS'), ('SS', 'SSD'), ('ES', 'ESP'), ('LK', 'LKA'), - ('SD', 'SDN'), ('SR', 'SUR'), ('SJ', 'SJM'), ('SZ', 'SWZ'), ('SE', 'SWE'), - ('CH', 'CHE'), ('SY', 'SYR'), ('TW', 'TWN'), ('TJ', 'TJK'), ('TZ', 'TZA'), - ('TH', 'THA'), ('TL', 'TLS'), ('TG', 'TGO'), ('TK', 'TKL'), ('TO', 'TON'), - ('TT', 'TTO'), ('TN', 'TUN'), ('TR', 'TUR'), ('TM', 'TKM'), ('TC', 'TCA'), - ('TV', 'TUV'), ('UG', 'UGA'), ('UA', 'UKR'), ('AE', 'ARE'), ('GB', 'GBR'), - ('US', 'USA'), ('UM', 'UMI'), ('UY', 'URY'), ('UZ', 'UZB'), ('VU', 'VUT'), - ('VE', 'VEN'), ('VN', 'VNM'), ('VG', 'VGB'), ('VI', 'VIR'), ('WF', 'WLF'), - ('EH', 'ESH'), ('YE', 'YEM'), ('ZM', 'ZMB'), ('ZW', 'ZWE') + ("AF", "AFG"), + ("AX", "ALA"), + ("AL", "ALB"), + ("DZ", "DZA"), + ("AS", "ASM"), + ("AD", "AND"), + ("AO", "AGO"), + ("AI", "AIA"), + ("AQ", "ATA"), + ("AG", "ATG"), + ("AR", "ARG"), + ("AM", "ARM"), + ("AW", "ABW"), + ("AU", "AUS"), + ("AT", "AUT"), + ("AZ", "AZE"), + ("BS", "BHS"), + ("BH", "BHR"), + ("BD", "BGD"), + ("BB", "BRB"), + ("BY", "BLR"), + ("BE", "BEL"), + ("BZ", "BLZ"), + ("BJ", "BEN"), + ("BM", "BMU"), + ("BT", "BTN"), + ("BO", "BOL"), + ("BQ", "BES"), + ("BA", "BIH"), + ("BW", "BWA"), + ("BV", "BVT"), + ("BR", "BRA"), + ("IO", "IOT"), + ("BN", "BRN"), + ("BG", "BGR"), + ("BF", "BFA"), + ("BI", "BDI"), + ("KH", "KHM"), + ("CM", "CMR"), + ("CA", "CAN"), + ("CV", "CPV"), + ("KY", "CYM"), + ("CF", "CAF"), + ("TD", "TCD"), + ("CL", "CHL"), + ("CN", "CHN"), + ("CX", "CXR"), + ("CC", "CCK"), + ("CO", "COL"), + ("KM", "COM"), + ("CG", "COG"), + ("CD", "COD"), + ("CK", "COK"), + ("CR", "CRI"), + ("CI", "CIV"), + ("HR", "HRV"), + ("CU", "CUB"), + ("CW", "CUW"), + ("CY", "CYP"), + ("CZ", "CZE"), + ("DK", "DNK"), + ("DJ", "DJI"), + ("DM", "DMA"), + ("DO", "DOM"), + ("EC", "ECU"), + ("EG", "EGY"), + ("SV", "SLV"), + ("GQ", "GNQ"), + ("ER", "ERI"), + ("EE", "EST"), + ("ET", "ETH"), + ("FK", "FLK"), + ("FO", "FRO"), + ("FJ", "FJI"), + ("FI", "FIN"), + ("FR", "FRA"), + ("GF", "GUF"), + ("PF", "PYF"), + ("TF", "ATF"), + ("GA", "GAB"), + ("GM", "GMB"), + ("GE", "GEO"), + ("DE", "DEU"), + ("GH", "GHA"), + ("GI", "GIB"), + ("GR", "GRC"), + ("GL", "GRL"), + ("GD", "GRD"), + ("GP", "GLP"), + ("GU", "GUM"), + ("GT", "GTM"), + ("GG", "GGY"), + ("GN", "GIN"), + ("GW", "GNB"), + ("GY", "GUY"), + ("HT", "HTI"), + ("HM", "HMD"), + ("VA", "VAT"), + ("HN", "HND"), + ("HK", "HKG"), + ("HU", "HUN"), + ("IS", "ISL"), + ("IN", "IND"), + ("ID", "IDN"), + ("IR", "IRN"), + ("IQ", "IRQ"), + ("IE", "IRL"), + ("IM", "IMN"), + ("IL", "ISR"), + ("IT", "ITA"), + ("JM", "JAM"), + ("JP", "JPN"), + ("JE", "JEY"), + ("JO", "JOR"), + ("KZ", "KAZ"), + ("KE", "KEN"), + ("KI", "KIR"), + ("KP", "PRK"), + ("KR", "KOR"), + ("KW", "KWT"), + ("KG", "KGZ"), + ("LA", "LAO"), + ("LV", "LVA"), + ("LB", "LBN"), + ("LS", "LSO"), + ("LR", "LBR"), + ("LY", "LBY"), + ("LI", "LIE"), + ("LT", "LTU"), + ("LU", "LUX"), + ("MO", "MAC"), + ("MK", "MKD"), + ("MG", "MDG"), + ("MW", "MWI"), + ("MY", "MYS"), + ("MV", "MDV"), + ("ML", "MLI"), + ("MT", "MLT"), + ("MH", "MHL"), + ("MQ", "MTQ"), + ("MR", "MRT"), + ("MU", "MUS"), + ("YT", "MYT"), + ("MX", "MEX"), + ("FM", "FSM"), + ("MD", "MDA"), + ("MC", "MCO"), + ("MN", "MNG"), + ("ME", "MNE"), + ("MS", "MSR"), + ("MA", "MAR"), + ("MZ", "MOZ"), + ("MM", "MMR"), + ("NA", "NAM"), + ("NR", "NRU"), + ("NP", "NPL"), + ("NL", "NLD"), + ("NC", "NCL"), + ("NZ", "NZL"), + ("NI", "NIC"), + ("NE", "NER"), + ("NG", "NGA"), + ("NU", "NIU"), + ("NF", "NFK"), + ("MP", "MNP"), + ("NO", "NOR"), + ("OM", "OMN"), + ("PK", "PAK"), + ("PW", "PLW"), + ("PS", "PSE"), + ("PA", "PAN"), + ("PG", "PNG"), + ("PY", "PRY"), + ("PE", "PER"), + ("PH", "PHL"), + ("PN", "PCN"), + ("PL", "POL"), + ("PT", "PRT"), + ("PR", "PRI"), + ("QA", "QAT"), + ("RE", "REU"), + ("RO", "ROU"), + ("RU", "RUS"), + ("RW", "RWA"), + ("BL", "BLM"), + ("SH", "SHN"), + ("KN", "KNA"), + ("LC", "LCA"), + ("MF", "MAF"), + ("PM", "SPM"), + ("VC", "VCT"), + ("WS", "WSM"), + ("SM", "SMR"), + ("ST", "STP"), + ("SA", "SAU"), + ("SN", "SEN"), + ("RS", "SRB"), + ("SC", "SYC"), + ("SL", "SLE"), + ("SG", "SGP"), + ("SX", "SXM"), + ("SK", "SVK"), + ("SI", "SVN"), + ("SB", "SLB"), + ("SO", "SOM"), + ("ZA", "ZAF"), + ("GS", "SGS"), + ("SS", "SSD"), + ("ES", "ESP"), + ("LK", "LKA"), + ("SD", "SDN"), + ("SR", "SUR"), + ("SJ", "SJM"), + ("SZ", "SWZ"), + ("SE", "SWE"), + ("CH", "CHE"), + ("SY", "SYR"), + ("TW", "TWN"), + ("TJ", "TJK"), + ("TZ", "TZA"), + ("TH", "THA"), + ("TL", "TLS"), + ("TG", "TGO"), + ("TK", "TKL"), + ("TO", "TON"), + ("TT", "TTO"), + ("TN", "TUN"), + ("TR", "TUR"), + ("TM", "TKM"), + ("TC", "TCA"), + ("TV", "TUV"), + ("UG", "UGA"), + ("UA", "UKR"), + ("AE", "ARE"), + ("GB", "GBR"), + ("US", "USA"), + ("UM", "UMI"), + ("UY", "URY"), + ("UZ", "UZB"), + ("VU", "VUT"), + ("VE", "VEN"), + ("VN", "VNM"), + ("VG", "VGB"), + ("VI", "VIR"), + ("WF", "WLF"), + ("EH", "ESH"), + ("YE", "YEM"), + ("ZM", "ZMB"), + ("ZW", "ZWE"), ) diff --git a/src/ralph/assets/invoice_report.py b/src/ralph/assets/invoice_report.py index bcfbca8c90..a430e283f9 100644 --- a/src/ralph/assets/invoice_report.py +++ b/src/ralph/assets/invoice_report.py @@ -23,17 +23,21 @@ class ReportTemplateNotDefined(ValidationError): class InvoiceReportMixin(object): - actions = ['invoice_report'] + actions = ["invoice_report"] _invoice_report_select_related = [] _invoice_report_common_fields = [ - 'invoice_no', 'invoice_date', 'provider', 'price_currency', 'property_of__name' + "invoice_no", + "invoice_date", + "provider", + "price_currency", + "property_of__name", ] - _price_field = 'price' - _invoice_report_name = 'invoice' + _price_field = "price" + _invoice_report_name = "invoice" _invoice_report_item_fields = [] - _invoice_report_empty_value = '-' - _invoice_report_datetime_format = '%Y-%m-%d %H:%M:%S' + _invoice_report_empty_value = "-" + _invoice_report_datetime_format = "%Y-%m-%d %H:%M:%S" def invoice_report(self, request, queryset): """ @@ -45,7 +49,8 @@ def invoice_report(self, request, queryset): return self._generate_invoice_report(request, queryset) except ValidationError as e: messages.error(request, e.message) - invoice_report.short_description = _('Invoice report') + + invoice_report.short_description = _("Invoice report") def _validate(self, queryset): """ @@ -58,9 +63,11 @@ def _validate(self, queryset): if values_distinct.count() != 1: raise ValidationError(self._get_non_unique_error(queryset)) if not all(values_distinct[0].values()): - raise ValidationError("None of {} can't be empty".format(', '.join( - self._invoice_report_common_fields - ))) + raise ValidationError( + "None of {} can't be empty".format( + ", ".join(self._invoice_report_common_fields) + ) + ) def _get_non_unique_error(self, queryset): """ @@ -70,35 +77,33 @@ def _get_non_unique_error(self, queryset): for field in self._invoice_report_common_fields: items = queryset.values(field).distinct() if items.count() != 1: - if field == 'invoice_date': - data = ', '.join( + if field == "invoice_date": + data = ", ".join( item[field].strftime("%Y-%m-%d") - for item in items if item[field] + for item in items + if item[field] ) else: - data = ', '.join( - item[field] for item in items if item[field] - ) + data = ", ".join(item[field] for item in items if item[field]) non_unique[field] = data - non_unique_items = ' '.join([ - '{}: {}'.format(key, value) - for key, value in non_unique.items() if value - ]) - return '{}: {}'.format( - _('Selected items have different'), non_unique_items, + non_unique_items = " ".join( + ["{}: {}".format(key, value) for key, value in non_unique.items() if value] + ) + return "{}: {}".format( + _("Selected items have different"), + non_unique_items, ) def _generate_invoice_report(self, request, queryset): """ Generate invoice report when data (queryset) is valid. """ - logger.info('Generating invoice report for model {}'.format( - queryset.model - )) + logger.info("Generating invoice report for model {}".format(queryset.model)) data = self._get_report_data(request, queryset) content = self._get_pdf_content(data) - file_name = '{}-{}.pdf'.format( - self._invoice_report_name, data['id'], + file_name = "{}-{}.pdf".format( + self._invoice_report_name, + data["id"], ) return generate_pdf_response(content, file_name) @@ -109,29 +114,28 @@ def _get_report_data(self, request, queryset): """ first_item = queryset[0] data = { - 'id': str(slugify(first_item.invoice_no)), - 'property_of_id': ( - first_item.property_of.id - if first_item.property_of else None + "id": str(slugify(first_item.invoice_no)), + "property_of_id": ( + first_item.property_of.id if first_item.property_of else None ), - 'model': queryset.model._meta.model_name, - 'base_info': { - 'invoice_no': first_item.invoice_no, - 'invoice_date': str(first_item.invoice_date), - 'provider': first_item.provider, - 'datetime': datetime.datetime.now().strftime( + "model": queryset.model._meta.model_name, + "base_info": { + "invoice_no": first_item.invoice_no, + "invoice_date": str(first_item.invoice_date), + "provider": first_item.provider, + "datetime": datetime.datetime.now().strftime( self._invoice_report_datetime_format ), - 'property_of': first_item.property_of.name, + "property_of": first_item.property_of.name, }, - 'items': list(map(self._parse_item, queryset)), - 'sum_price': str( - queryset.aggregate( - Sum(self._price_field) - ).get('{}__sum'.format(self._price_field)) - ) + "items": list(map(self._parse_item, queryset)), + "sum_price": str( + queryset.aggregate(Sum(self._price_field)).get( + "{}__sum".format(self._price_field) + ) + ), } - logger.info('Invoice report data: {}'.format(data)) + logger.info("Invoice report data: {}".format(data)) return data def _get_pdf_content(self, data): @@ -140,16 +144,18 @@ def _get_pdf_content(self, data): template = report.templates.filter(default=True).first() except (Report.DoesNotExist, ReportTemplate.DoesNotExist): raise ReportTemplateNotDefined( - 'Template for invoice report is not defined!' + "Template for invoice report is not defined!" + ) + logger.info( + "Using report {} and template {}".format( + report.name, template.template.path ) - logger.info('Using report {} and template {}'.format( - report.name, template.template.path - )) - template_content = '' - with open(template.template.path, 'rb') as f: + ) + template_content = "" + with open(template.template.path, "rb") as f: template_content = f.read() - service_pdf = ExternalService('PDF') + service_pdf = ExternalService("PDF") # Make sure data is JSON-serializable # Will throw otherwise data = json.loads(json.dumps(data)) @@ -180,9 +186,12 @@ def _parse_item(self, item): elif isinstance(val, datetime.datetime): val = val.strftime(self._invoice_report_datetime_format) elif isinstance(val, Money): - val_currency = '{}_currency'.format(self._price_field) - result[val_currency] = str(val.currency) \ - if val.currency else self._invoice_report_empty_value + val_currency = "{}_currency".format(self._price_field) + result[val_currency] = ( + str(val.currency) + if val.currency + else self._invoice_report_empty_value + ) val = val.amount result[f] = str(val) if val else self._invoice_report_empty_value @@ -192,10 +201,15 @@ def _parse_item(self, item): class AssetInvoiceReportMixin(InvoiceReportMixin): _invoice_report_empty_value = None - _invoice_report_select_related = [ - 'model', 'model__manufacturer', 'property_of' - ] + _invoice_report_select_related = ["model", "model__manufacturer", "property_of"] _invoice_report_item_fields = [ - 'model', 'barcode', 'niw', 'sn', 'price', 'property_of', 'created', - 'model__get_type_display', 'start_usage' + "model", + "barcode", + "niw", + "sn", + "price", + "property_of", + "created", + "model__get_type_display", + "start_usage", ] diff --git a/src/ralph/assets/migrations/0001_initial.py b/src/ralph/assets/migrations/0001_initial.py index 49749242f2..0dfec36bf5 100644 --- a/src/ralph/assets/migrations/0001_initial.py +++ b/src/ralph/assets/migrations/0001_initial.py @@ -12,293 +12,813 @@ class Migration(migrations.Migration): - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), + ("contenttypes", "0002_remove_content_type_name"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('accounts', '0001_initial'), - ('taggit', '0002_auto_20150616_2121'), + ("accounts", "0001_initial"), + ("taggit", "0002_auto_20150616_2121"), ] operations = [ migrations.CreateModel( - name='AssetHolder', + name="AssetHolder", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', max_length=75)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("name", models.CharField(verbose_name="name", max_length=75)), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='AssetLastHostname', + name="AssetLastHostname", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('prefix', models.CharField(db_index=True, max_length=8)), - ('counter', models.PositiveIntegerField(default=1)), - ('postfix', models.CharField(db_index=True, max_length=8)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("prefix", models.CharField(db_index=True, max_length=8)), + ("counter", models.PositiveIntegerField(default=1)), + ("postfix", models.CharField(db_index=True, max_length=8)), ], ), migrations.CreateModel( - name='AssetModel', + name="AssetModel", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', max_length=75)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('type', models.PositiveIntegerField(verbose_name='type', choices=[(1, 'back office'), (2, 'data center'), (3, 'part'), (4, 'all')])), - ('power_consumption', models.PositiveIntegerField(verbose_name='Power consumption', blank=True, default=0)), - ('height_of_device', models.FloatField(verbose_name='Height of device', default=0, validators=[django.core.validators.MinValueValidator(0)], blank=True)), - ('cores_count', models.PositiveIntegerField(verbose_name='Cores count', blank=True, default=0)), - ('visualization_layout_front', models.PositiveIntegerField(verbose_name='visualization layout of front side', choices=[(1, 'N/A'), (2, '1x2'), (3, '2x8'), (4, '2x16 (A/B)'), (5, '4x2')], blank=True, default=1)), - ('visualization_layout_back', models.PositiveIntegerField(verbose_name='visualization layout of back side', choices=[(1, 'N/A'), (2, '1x2'), (3, '2x8'), (4, '2x16 (A/B)'), (5, '4x2')], blank=True, default=1)), - ('has_parent', models.BooleanField(default=False)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("name", models.CharField(verbose_name="name", max_length=75)), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ( + "type", + models.PositiveIntegerField( + verbose_name="type", + choices=[ + (1, "back office"), + (2, "data center"), + (3, "part"), + (4, "all"), + ], + ), + ), + ( + "power_consumption", + models.PositiveIntegerField( + verbose_name="Power consumption", blank=True, default=0 + ), + ), + ( + "height_of_device", + models.FloatField( + verbose_name="Height of device", + default=0, + validators=[django.core.validators.MinValueValidator(0)], + blank=True, + ), + ), + ( + "cores_count", + models.PositiveIntegerField( + verbose_name="Cores count", blank=True, default=0 + ), + ), + ( + "visualization_layout_front", + models.PositiveIntegerField( + verbose_name="visualization layout of front side", + choices=[ + (1, "N/A"), + (2, "1x2"), + (3, "2x8"), + (4, "2x16 (A/B)"), + (5, "4x2"), + ], + blank=True, + default=1, + ), + ), + ( + "visualization_layout_back", + models.PositiveIntegerField( + verbose_name="visualization layout of back side", + choices=[ + (1, "N/A"), + (2, "1x2"), + (3, "2x8"), + (4, "2x16 (A/B)"), + (5, "4x2"), + ], + blank=True, + default=1, + ), + ), + ("has_parent", models.BooleanField(default=False)), ], options={ - 'verbose_name': 'model', - 'verbose_name_plural': 'models', + "verbose_name": "model", + "verbose_name_plural": "models", }, ), migrations.CreateModel( - name='BaseObject', + name="BaseObject", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('remarks', models.TextField(blank=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ("remarks", models.TextField(blank=True)), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='BudgetInfo', + name="BudgetInfo", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'verbose_name': 'Budget info', - 'verbose_name_plural': 'Budgets info', + "verbose_name": "Budget info", + "verbose_name_plural": "Budgets info", }, ), migrations.CreateModel( - name='BusinessSegment', + name="BusinessSegment", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='Category', + name="Category", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', max_length=75)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('code', models.CharField(blank=True, default='', max_length=4)), - ('imei_required', models.BooleanField(default=False)), - ('lft', models.PositiveIntegerField(editable=False, db_index=True)), - ('rght', models.PositiveIntegerField(editable=False, db_index=True)), - ('tree_id', models.PositiveIntegerField(editable=False, db_index=True)), - ('level', models.PositiveIntegerField(editable=False, db_index=True)), - ('parent', mptt.fields.TreeForeignKey(to='assets.Category', blank=True, null=True, related_name='children', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("name", models.CharField(verbose_name="name", max_length=75)), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ("code", models.CharField(blank=True, default="", max_length=4)), + ("imei_required", models.BooleanField(default=False)), + ("lft", models.PositiveIntegerField(editable=False, db_index=True)), + ("rght", models.PositiveIntegerField(editable=False, db_index=True)), + ("tree_id", models.PositiveIntegerField(editable=False, db_index=True)), + ("level", models.PositiveIntegerField(editable=False, db_index=True)), + ( + "parent", + mptt.fields.TreeForeignKey( + to="assets.Category", + blank=True, + null=True, + related_name="children", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'category', - 'verbose_name_plural': 'categories', + "verbose_name": "category", + "verbose_name_plural": "categories", }, ), migrations.CreateModel( - name='ComponentModel', + name="ComponentModel", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('speed', models.PositiveIntegerField(verbose_name='speed (MHz)', blank=True, default=0)), - ('cores', models.PositiveIntegerField(verbose_name='number of cores', blank=True, default=0)), - ('size', models.PositiveIntegerField(verbose_name='size (MiB)', blank=True, default=0)), - ('type', models.PositiveIntegerField(verbose_name='component type', choices=[(1, 'processor'), (2, 'memory'), (3, 'disk drive'), (4, 'ethernet card'), (5, 'expansion card'), (6, 'fibre channel card'), (7, 'disk share'), (8, 'unknown'), (9, 'management'), (10, 'power module'), (11, 'cooling device'), (12, 'media tray'), (13, 'chassis'), (14, 'backup'), (15, 'software'), (16, 'operating system')], default=8)), - ('family', models.CharField(blank=True, default='', max_length=128)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "speed", + models.PositiveIntegerField( + verbose_name="speed (MHz)", blank=True, default=0 + ), + ), + ( + "cores", + models.PositiveIntegerField( + verbose_name="number of cores", blank=True, default=0 + ), + ), + ( + "size", + models.PositiveIntegerField( + verbose_name="size (MiB)", blank=True, default=0 + ), + ), + ( + "type", + models.PositiveIntegerField( + verbose_name="component type", + choices=[ + (1, "processor"), + (2, "memory"), + (3, "disk drive"), + (4, "ethernet card"), + (5, "expansion card"), + (6, "fibre channel card"), + (7, "disk share"), + (8, "unknown"), + (9, "management"), + (10, "power module"), + (11, "cooling device"), + (12, "media tray"), + (13, "chassis"), + (14, "backup"), + (15, "software"), + (16, "operating system"), + ], + default=8, + ), + ), + ("family", models.CharField(blank=True, default="", max_length=128)), ], options={ - 'verbose_name': 'component model', - 'verbose_name_plural': 'component models', + "verbose_name": "component model", + "verbose_name_plural": "component models", }, ), migrations.CreateModel( - name='Environment', + name="Environment", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='GenericComponent', + name="GenericComponent", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('label', models.CharField(verbose_name='label', blank=True, default=None, null=True, max_length=255)), - ('sn', ralph.lib.mixins.fields.NullableCharField(default=None, unique=True, max_length=255, verbose_name='vendor SN', blank=True, null=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "label", + models.CharField( + verbose_name="label", + blank=True, + default=None, + null=True, + max_length=255, + ), + ), + ( + "sn", + ralph.lib.mixins.fields.NullableCharField( + default=None, + unique=True, + max_length=255, + verbose_name="vendor SN", + blank=True, + null=True, + ), + ), ], options={ - 'verbose_name': 'generic component', - 'verbose_name_plural': 'generic components', + "verbose_name": "generic component", + "verbose_name_plural": "generic components", }, ), migrations.CreateModel( - name='Manufacturer', + name="Manufacturer", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='ProfitCenter', + name="ProfitCenter", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('description', models.TextField(blank=True)), - ('business_segment', models.ForeignKey(to='assets.BusinessSegment', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ("description", models.TextField(blank=True)), + ( + "business_segment", + models.ForeignKey( + to="assets.BusinessSegment", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='Service', + name="Service", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('active', models.BooleanField(default=True)), - ('uid', ralph.lib.mixins.fields.NullableCharField(blank=True, null=True, unique=True, max_length=40)), - ('cost_center', models.CharField(blank=True, max_length=100)), - ('business_owners', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, related_name='services_business_owner')), - ('profit_center', models.ForeignKey(to='assets.ProfitCenter', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE)), - ('support_team', models.ForeignKey(to='accounts.Team', blank=True, null=True, related_name='services', on_delete=django.db.models.deletion.CASCADE)), - ('technical_owners', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, related_name='services_technical_owner')), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ("active", models.BooleanField(default=True)), + ( + "uid", + ralph.lib.mixins.fields.NullableCharField( + blank=True, null=True, unique=True, max_length=40 + ), + ), + ("cost_center", models.CharField(blank=True, max_length=100)), + ( + "business_owners", + models.ManyToManyField( + blank=True, + to=settings.AUTH_USER_MODEL, + related_name="services_business_owner", + ), + ), + ( + "profit_center", + models.ForeignKey( + to="assets.ProfitCenter", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "support_team", + models.ForeignKey( + to="accounts.Team", + blank=True, + null=True, + related_name="services", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "technical_owners", + models.ManyToManyField( + blank=True, + to=settings.AUTH_USER_MODEL, + related_name="services_technical_owner", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='Asset', + name="Asset", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), - ('hostname', models.CharField(verbose_name='hostname', blank=True, default=None, null=True, max_length=255)), - ('sn', ralph.lib.mixins.fields.NullableCharField(verbose_name='SN', blank=True, null=True, unique=True, max_length=200)), - ('barcode', ralph.lib.mixins.fields.NullableCharField(default=None, unique=True, max_length=200, verbose_name='barcode', blank=True, null=True)), - ('niw', ralph.lib.mixins.fields.NullableCharField(verbose_name='Inventory number', blank=True, default=None, null=True, max_length=200)), - ('required_support', models.BooleanField(default=False)), - ('order_no', models.CharField(blank=True, null=True, max_length=50)), - ('invoice_no', models.CharField(blank=True, db_index=True, null=True, max_length=128)), - ('invoice_date', models.DateField(blank=True, null=True)), - ('price', models.DecimalField(blank=True, default=0, null=True, decimal_places=2, max_digits=10)), - ('provider', models.CharField(blank=True, null=True, max_length=100)), - ('depreciation_rate', models.DecimalField(blank=True, default=25, help_text='This value is in percentage. For example value: "100" means it depreciates during a year. Value: "25" means it depreciates during 4 years, and so on... .', max_digits=5, decimal_places=2)), - ('force_depreciation', models.BooleanField(help_text='Check if you no longer want to bill for this asset')), - ('depreciation_end_date', models.DateField(blank=True, null=True)), - ('task_url', models.URLField(blank=True, null=True, help_text='External workflow system URL', max_length=2048)), - ('budget_info', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, default=None, to='assets.BudgetInfo', blank=True, null=True)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "hostname", + models.CharField( + verbose_name="hostname", + blank=True, + default=None, + null=True, + max_length=255, + ), + ), + ( + "sn", + ralph.lib.mixins.fields.NullableCharField( + verbose_name="SN", + blank=True, + null=True, + unique=True, + max_length=200, + ), + ), + ( + "barcode", + ralph.lib.mixins.fields.NullableCharField( + default=None, + unique=True, + max_length=200, + verbose_name="barcode", + blank=True, + null=True, + ), + ), + ( + "niw", + ralph.lib.mixins.fields.NullableCharField( + verbose_name="Inventory number", + blank=True, + default=None, + null=True, + max_length=200, + ), + ), + ("required_support", models.BooleanField(default=False)), + ("order_no", models.CharField(blank=True, null=True, max_length=50)), + ( + "invoice_no", + models.CharField( + blank=True, db_index=True, null=True, max_length=128 + ), + ), + ("invoice_date", models.DateField(blank=True, null=True)), + ( + "price", + models.DecimalField( + blank=True, + default=0, + null=True, + decimal_places=2, + max_digits=10, + ), + ), + ("provider", models.CharField(blank=True, null=True, max_length=100)), + ( + "depreciation_rate", + models.DecimalField( + blank=True, + default=25, + help_text='This value is in percentage. For example value: "100" means it depreciates during a year. Value: "25" means it depreciates during 4 years, and so on... .', + max_digits=5, + decimal_places=2, + ), + ), + ( + "force_depreciation", + models.BooleanField( + help_text="Check if you no longer want to bill for this asset" + ), + ), + ("depreciation_end_date", models.DateField(blank=True, null=True)), + ( + "task_url", + models.URLField( + blank=True, + null=True, + help_text="External workflow system URL", + max_length=2048, + ), + ), + ( + "budget_info", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + default=None, + to="assets.BudgetInfo", + blank=True, + null=True, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject'), + bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, "assets.baseobject"), ), migrations.CreateModel( - name='ServiceEnvironment', + name="ServiceEnvironment", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), - ('environment', models.ForeignKey(to='assets.Environment', on_delete=django.db.models.deletion.CASCADE)), - ('service', models.ForeignKey(to='assets.Service', on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "environment", + models.ForeignKey( + to="assets.Environment", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "service", + models.ForeignKey( + to="assets.Service", on_delete=django.db.models.deletion.CASCADE + ), + ), ], - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.AddField( - model_name='genericcomponent', - name='base_object', - field=models.ForeignKey(to='assets.BaseObject', related_name='genericcomponent', on_delete=django.db.models.deletion.CASCADE), + model_name="genericcomponent", + name="base_object", + field=models.ForeignKey( + to="assets.BaseObject", + related_name="genericcomponent", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='genericcomponent', - name='model', - field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, default=None, verbose_name='model', to='assets.ComponentModel', blank=True, null=True), + model_name="genericcomponent", + name="model", + field=models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + default=None, + verbose_name="model", + to="assets.ComponentModel", + blank=True, + null=True, + ), ), migrations.AlterUniqueTogether( - name='componentmodel', - unique_together=set([('speed', 'cores', 'size', 'type', 'family')]), + name="componentmodel", + unique_together=set([("speed", "cores", "size", "type", "family")]), ), migrations.AddField( - model_name='baseobject', - name='content_type', - field=models.ForeignKey(to='contenttypes.ContentType', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="baseobject", + name="content_type", + field=models.ForeignKey( + to="contenttypes.ContentType", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='baseobject', - name='parent', - field=models.ForeignKey(to='assets.BaseObject', blank=True, null=True, related_name='children', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobject", + name="parent", + field=models.ForeignKey( + to="assets.BaseObject", + blank=True, + null=True, + related_name="children", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='baseobject', - name='tags', - field=taggit.managers.TaggableManager(through='taggit.TaggedItem', verbose_name='Tags', blank=True, to='taggit.Tag', help_text='A comma-separated list of tags.'), + model_name="baseobject", + name="tags", + field=taggit.managers.TaggableManager( + through="taggit.TaggedItem", + verbose_name="Tags", + blank=True, + to="taggit.Tag", + help_text="A comma-separated list of tags.", + ), ), migrations.AddField( - model_name='assetmodel', - name='category', - field=mptt.fields.TreeForeignKey(to='assets.Category', null=True, related_name='models', on_delete=django.db.models.deletion.CASCADE), + model_name="assetmodel", + name="category", + field=mptt.fields.TreeForeignKey( + to="assets.Category", + null=True, + related_name="models", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='assetmodel', - name='manufacturer', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.Manufacturer', blank=True, null=True), + model_name="assetmodel", + name="manufacturer", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="assets.Manufacturer", + blank=True, + null=True, + ), ), migrations.AlterUniqueTogether( - name='assetlasthostname', - unique_together=set([('prefix', 'postfix')]), + name="assetlasthostname", + unique_together=set([("prefix", "postfix")]), ), migrations.AddField( - model_name='service', - name='environments', - field=models.ManyToManyField(through='assets.ServiceEnvironment', to='assets.Environment'), + model_name="service", + name="environments", + field=models.ManyToManyField( + through="assets.ServiceEnvironment", to="assets.Environment" + ), ), migrations.AddField( - model_name='baseobject', - name='service_env', - field=models.ForeignKey(to='assets.ServiceEnvironment', null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="baseobject", + name="service_env", + field=models.ForeignKey( + to="assets.ServiceEnvironment", + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='asset', - name='model', - field=models.ForeignKey(to='assets.AssetModel', related_name='assets', on_delete=django.db.models.deletion.CASCADE), + model_name="asset", + name="model", + field=models.ForeignKey( + to="assets.AssetModel", + related_name="assets", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='asset', - name='property_of', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.AssetHolder', blank=True, null=True), + model_name="asset", + name="property_of", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="assets.AssetHolder", + blank=True, + null=True, + ), ), migrations.AlterUniqueTogether( - name='serviceenvironment', - unique_together=set([('service', 'environment')]), + name="serviceenvironment", + unique_together=set([("service", "environment")]), ), ] diff --git a/src/ralph/assets/migrations/0002_auto_20151125_1354.py b/src/ralph/assets/migrations/0002_auto_20151125_1354.py index dea6af5cd0..eff62f962f 100644 --- a/src/ralph/assets/migrations/0002_auto_20151125_1354.py +++ b/src/ralph/assets/migrations/0002_auto_20151125_1354.py @@ -5,90 +5,89 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0001_initial'), + ("assets", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='assetholder', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="assetholder", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='assetholder', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="assetholder", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='assetmodel', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="assetmodel", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='assetmodel', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="assetmodel", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='baseobject', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="baseobject", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='baseobject', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="baseobject", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='budgetinfo', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="budgetinfo", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='budgetinfo', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="budgetinfo", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='category', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="category", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='category', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="category", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='environment', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="environment", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='environment', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="environment", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='manufacturer', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="manufacturer", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='manufacturer', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="manufacturer", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='service', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="service", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='service', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="service", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), ] diff --git a/src/ralph/assets/migrations/0003_auto_20151126_2205.py b/src/ralph/assets/migrations/0003_auto_20151126_2205.py index ad9348bb04..ee34ab83bf 100644 --- a/src/ralph/assets/migrations/0003_auto_20151126_2205.py +++ b/src/ralph/assets/migrations/0003_auto_20151126_2205.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0002_auto_20151125_1354'), + ("assets", "0002_auto_20151125_1354"), ] operations = [ migrations.AlterField( - model_name='asset', - name='force_depreciation', - field=models.BooleanField(default=False, help_text='Check if you no longer want to bill for this asset'), + model_name="asset", + name="force_depreciation", + field=models.BooleanField( + default=False, + help_text="Check if you no longer want to bill for this asset", + ), ), ] diff --git a/src/ralph/assets/migrations/0004_auto_20151204_0758.py b/src/ralph/assets/migrations/0004_auto_20151204_0758.py index 9ba233633c..28377bf35f 100644 --- a/src/ralph/assets/migrations/0004_auto_20151204_0758.py +++ b/src/ralph/assets/migrations/0004_auto_20151204_0758.py @@ -1,38 +1,37 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('assets', '0003_auto_20151126_2205'), + ("assets", "0003_auto_20151126_2205"), ] operations = [ migrations.AlterModelOptions( - name='assetholder', - options={'ordering': ['name']}, + name="assetholder", + options={"ordering": ["name"]}, ), migrations.AlterModelOptions( - name='businesssegment', - options={'ordering': ['name']}, + name="businesssegment", + options={"ordering": ["name"]}, ), migrations.AlterModelOptions( - name='environment', - options={'ordering': ['name']}, + name="environment", + options={"ordering": ["name"]}, ), migrations.AlterModelOptions( - name='manufacturer', - options={'ordering': ['name']}, + name="manufacturer", + options={"ordering": ["name"]}, ), migrations.AlterModelOptions( - name='profitcenter', - options={'ordering': ['name']}, + name="profitcenter", + options={"ordering": ["name"]}, ), migrations.AlterModelOptions( - name='service', - options={'ordering': ['name']}, + name="service", + options={"ordering": ["name"]}, ), ] diff --git a/src/ralph/assets/migrations/0005_category_depreciation_rate.py b/src/ralph/assets/migrations/0005_category_depreciation_rate.py index 69c1708c7d..98cea7f12c 100644 --- a/src/ralph/assets/migrations/0005_category_depreciation_rate.py +++ b/src/ralph/assets/migrations/0005_category_depreciation_rate.py @@ -5,15 +5,20 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0004_auto_20151204_0758'), + ("assets", "0004_auto_20151204_0758"), ] operations = [ migrations.AddField( - model_name='category', - name='default_depreciation_rate', - field=models.DecimalField(help_text='This value is in percentage. For example value: "100" means it depreciates during a year. Value: "25" means it depreciates during 4 years, and so on... .', decimal_places=2, max_digits=5, blank=True, default=25), + model_name="category", + name="default_depreciation_rate", + field=models.DecimalField( + help_text='This value is in percentage. For example value: "100" means it depreciates during a year. Value: "25" means it depreciates during 4 years, and so on... .', + decimal_places=2, + max_digits=5, + blank=True, + default=25, + ), ), ] diff --git a/src/ralph/assets/migrations/0006_category_show_buyout_date.py b/src/ralph/assets/migrations/0006_category_show_buyout_date.py index 9567d13ab8..ba77149724 100644 --- a/src/ralph/assets/migrations/0006_category_show_buyout_date.py +++ b/src/ralph/assets/migrations/0006_category_show_buyout_date.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0005_category_depreciation_rate'), + ("assets", "0005_category_depreciation_rate"), ] operations = [ migrations.AddField( - model_name='category', - name='show_buyout_date', + model_name="category", + name="show_buyout_date", field=models.BooleanField(default=False), ), ] diff --git a/src/ralph/assets/migrations/0007_auto_20160122_1022.py b/src/ralph/assets/migrations/0007_auto_20160122_1022.py index f8bbf3413d..2ed84f51ff 100644 --- a/src/ralph/assets/migrations/0007_auto_20160122_1022.py +++ b/src/ralph/assets/migrations/0007_auto_20160122_1022.py @@ -5,20 +5,49 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0006_category_show_buyout_date'), + ("assets", "0006_category_show_buyout_date"), ] operations = [ migrations.AlterField( - model_name='assetmodel', - name='visualization_layout_back', - field=models.PositiveIntegerField(verbose_name='visualization layout of back side', choices=[(1, 'N/A'), (2, '1 row x 2 columns'), (3, '2 rows x 8 columns'), (4, '2 rows x 16 columns (A/B)'), (5, '4 rows x 2 columns'), (6, '2 rows x 4 columns'), (7, '2 rows x 2 columns'), (8, '1 rows x 14 columns'), (9, '2 rows x 1 columns')], default=1, blank=True), + model_name="assetmodel", + name="visualization_layout_back", + field=models.PositiveIntegerField( + verbose_name="visualization layout of back side", + choices=[ + (1, "N/A"), + (2, "1 row x 2 columns"), + (3, "2 rows x 8 columns"), + (4, "2 rows x 16 columns (A/B)"), + (5, "4 rows x 2 columns"), + (6, "2 rows x 4 columns"), + (7, "2 rows x 2 columns"), + (8, "1 rows x 14 columns"), + (9, "2 rows x 1 columns"), + ], + default=1, + blank=True, + ), ), migrations.AlterField( - model_name='assetmodel', - name='visualization_layout_front', - field=models.PositiveIntegerField(verbose_name='visualization layout of front side', choices=[(1, 'N/A'), (2, '1 row x 2 columns'), (3, '2 rows x 8 columns'), (4, '2 rows x 16 columns (A/B)'), (5, '4 rows x 2 columns'), (6, '2 rows x 4 columns'), (7, '2 rows x 2 columns'), (8, '1 rows x 14 columns'), (9, '2 rows x 1 columns')], default=1, blank=True), + model_name="assetmodel", + name="visualization_layout_front", + field=models.PositiveIntegerField( + verbose_name="visualization layout of front side", + choices=[ + (1, "N/A"), + (2, "1 row x 2 columns"), + (3, "2 rows x 8 columns"), + (4, "2 rows x 16 columns (A/B)"), + (5, "4 rows x 2 columns"), + (6, "2 rows x 4 columns"), + (7, "2 rows x 2 columns"), + (8, "1 rows x 14 columns"), + (9, "2 rows x 1 columns"), + ], + default=1, + blank=True, + ), ), ] diff --git a/src/ralph/assets/migrations/0008_auto_20160122_1429.py b/src/ralph/assets/migrations/0008_auto_20160122_1429.py index cc647a5c72..4f59e152ec 100644 --- a/src/ralph/assets/migrations/0008_auto_20160122_1429.py +++ b/src/ralph/assets/migrations/0008_auto_20160122_1429.py @@ -6,25 +6,30 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0007_auto_20160122_1022'), + ("assets", "0007_auto_20160122_1022"), ] operations = [ migrations.AlterField( - model_name='assetmodel', - name='cores_count', - field=models.PositiveIntegerField(verbose_name='Cores count', default=0), + model_name="assetmodel", + name="cores_count", + field=models.PositiveIntegerField(verbose_name="Cores count", default=0), ), migrations.AlterField( - model_name='assetmodel', - name='height_of_device', - field=models.FloatField(verbose_name='Height of device', validators=[django.core.validators.MinValueValidator(0)], default=0), + model_name="assetmodel", + name="height_of_device", + field=models.FloatField( + verbose_name="Height of device", + validators=[django.core.validators.MinValueValidator(0)], + default=0, + ), ), migrations.AlterField( - model_name='assetmodel', - name='power_consumption', - field=models.PositiveIntegerField(verbose_name='Power consumption', default=0), + model_name="assetmodel", + name="power_consumption", + field=models.PositiveIntegerField( + verbose_name="Power consumption", default=0 + ), ), ] diff --git a/src/ralph/assets/migrations/0009_auto_20160307_1138.py b/src/ralph/assets/migrations/0009_auto_20160307_1138.py index 305331cb55..eb98f65e8b 100644 --- a/src/ralph/assets/migrations/0009_auto_20160307_1138.py +++ b/src/ralph/assets/migrations/0009_auto_20160307_1138.py @@ -1,20 +1,25 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.models class Migration(migrations.Migration): - dependencies = [ - ('assets', '0008_auto_20160122_1429'), + ("assets", "0008_auto_20160122_1429"), ] operations = [ migrations.AlterField( - model_name='baseobject', - name='tags', - field=ralph.lib.mixins.models.TaggableManager(blank=True, verbose_name='Tags', help_text='A comma-separated list of tags.', to='taggit.Tag', through='taggit.TaggedItem'), + model_name="baseobject", + name="tags", + field=ralph.lib.mixins.models.TaggableManager( + blank=True, + verbose_name="Tags", + help_text="A comma-separated list of tags.", + to="taggit.Tag", + through="taggit.TaggedItem", + ), ), ] diff --git a/src/ralph/assets/migrations/0010_auto_20160405_1531.py b/src/ralph/assets/migrations/0010_auto_20160405_1531.py index 27f6bb4bcb..c9424ab015 100644 --- a/src/ralph/assets/migrations/0010_auto_20160405_1531.py +++ b/src/ralph/assets/migrations/0010_auto_20160405_1531.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('assets', '0009_auto_20160307_1138'), + ("assets", "0009_auto_20160307_1138"), ] operations = [ migrations.AlterModelOptions( - name='service', + name="service", options={}, ), ] diff --git a/src/ralph/assets/migrations/0011_auto_20160603_0742.py b/src/ralph/assets/migrations/0011_auto_20160603_0742.py index 4cbf101532..8755530ac9 100644 --- a/src/ralph/assets/migrations/0011_auto_20160603_0742.py +++ b/src/ralph/assets/migrations/0011_auto_20160603_0742.py @@ -1,25 +1,24 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields def migrate_hostname(apps, schema_editor): - Asset = apps.get_model('assets', 'Asset') + Asset = apps.get_model("assets", "Asset") # update all assets where hostname is empty string to null hostname - Asset.objects.filter(hostname='').update(hostname=None) + Asset.objects.filter(hostname="").update(hostname=None) def rev_migrate_hostname(apps, schema_editor): - Asset = apps.get_model('assets', 'Asset') - Asset.objects.filter(hostname__isnull=True).update(hostname='') + Asset = apps.get_model("assets", "Asset") + Asset.objects.filter(hostname__isnull=True).update(hostname="") class Migration(migrations.Migration): - dependencies = [ - ('assets', '0010_auto_20160405_1531'), + ("assets", "0010_auto_20160405_1531"), ] operations = [ @@ -29,11 +28,17 @@ class Migration(migrations.Migration): # CharField in reverse migration to use `CharField.to_python` # (to get '') instead of `NullableCharField.to_python` # (which returns None) - rev_migrate_hostname + rev_migrate_hostname, ), migrations.AlterField( - model_name='asset', - name='hostname', - field=ralph.lib.mixins.fields.NullableCharField(default=None, max_length=255, blank=True, null=True, verbose_name='hostname'), + model_name="asset", + name="hostname", + field=ralph.lib.mixins.fields.NullableCharField( + default=None, + max_length=255, + blank=True, + null=True, + verbose_name="hostname", + ), ), ] diff --git a/src/ralph/assets/migrations/0012_auto_20160606_1409.py b/src/ralph/assets/migrations/0012_auto_20160606_1409.py index 9cf9166429..7abd199e0b 100644 --- a/src/ralph/assets/migrations/0012_auto_20160606_1409.py +++ b/src/ralph/assets/migrations/0012_auto_20160606_1409.py @@ -12,104 +12,275 @@ class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0003_region_country'), - ('assets', '0011_auto_20160603_0742'), + ("accounts", "0003_region_country"), + ("assets", "0011_auto_20160603_0742"), ] operations = [ migrations.CreateModel( - name='ConfigurationClass', + name="ConfigurationClass", fields=[ - ('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('class_name', models.CharField(validators=[django.core.validators.RegexValidator(regex='\\w+')], verbose_name='class name', help_text='ex. puppet class', max_length=255)), - ('path', models.TextField(editable=False, verbose_name='path', default='', help_text='path is constructed from name of module and name of class', blank=True)), + ( + "id", + models.AutoField( + auto_created=True, + verbose_name="ID", + serialize=False, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "class_name", + models.CharField( + validators=[ + django.core.validators.RegexValidator(regex="\\w+") + ], + verbose_name="class name", + help_text="ex. puppet class", + max_length=255, + ), + ), + ( + "path", + models.TextField( + editable=False, + verbose_name="path", + default="", + help_text="path is constructed from name of module and name of class", + blank=True, + ), + ), ], options={ - 'verbose_name': 'configuration class', - 'ordering': ('path',), + "verbose_name": "configuration class", + "ordering": ("path",), }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='ConfigurationModule', + name="ConfigurationModule", fields=[ - ('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('name', models.CharField(validators=[django.core.validators.RegexValidator(regex='\\w+')], verbose_name='name', help_text='module name (ex. directory name in puppet)', max_length=255)), - ('lft', models.PositiveIntegerField(editable=False, db_index=True)), - ('rght', models.PositiveIntegerField(editable=False, db_index=True)), - ('tree_id', models.PositiveIntegerField(editable=False, db_index=True)), - ('level', models.PositiveIntegerField(editable=False, db_index=True)), - ('parent', mptt.fields.TreeForeignKey(related_name='children_modules', verbose_name='parent module', to='assets.ConfigurationModule', default=None, blank=True, null=True, on_delete=django.db.models.deletion.CASCADE)), - ('support_team', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='team', to='accounts.Team', default=None, blank=True, null=True)), + ( + "id", + models.AutoField( + auto_created=True, + verbose_name="ID", + serialize=False, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "name", + models.CharField( + validators=[ + django.core.validators.RegexValidator(regex="\\w+") + ], + verbose_name="name", + help_text="module name (ex. directory name in puppet)", + max_length=255, + ), + ), + ("lft", models.PositiveIntegerField(editable=False, db_index=True)), + ("rght", models.PositiveIntegerField(editable=False, db_index=True)), + ("tree_id", models.PositiveIntegerField(editable=False, db_index=True)), + ("level", models.PositiveIntegerField(editable=False, db_index=True)), + ( + "parent", + mptt.fields.TreeForeignKey( + related_name="children_modules", + verbose_name="parent module", + to="assets.ConfigurationModule", + default=None, + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "support_team", + models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + verbose_name="team", + to="accounts.Team", + default=None, + blank=True, + null=True, + ), + ), ], options={ - 'verbose_name': 'configuration module', - 'ordering': ('parent__name', 'name'), + "verbose_name": "configuration module", + "ordering": ("parent__name", "name"), }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='Ethernet', + name="Ethernet", fields=[ - ('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('label', ralph.lib.mixins.fields.NullableCharField(verbose_name='name', max_length=255, blank=True, null=True)), - ('mac', ralph.lib.mixins.fields.NullableCharField(verbose_name='MAC address', validators=[django.core.validators.RegexValidator(message="'%(value)s' is not a valid MAC address.", regex=re.compile('^\\s*([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\\s*$', 32))], unique=True, max_length=24, blank=True, null=True)), - ('speed', models.PositiveIntegerField(verbose_name='speed', default=11, choices=[(1, '10 Mbps'), (2, '100 Mbps'), (3, '1 Gbps'), (4, '10 Gbps'), (5, '40 Gbps'), (6, '100 Gbps'), (11, 'unknown speed')])), - ('base_object', models.ForeignKey(related_name='ethernet', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('model', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='model', to='assets.ComponentModel', default=None, blank=True, null=True)), + ( + "id", + models.AutoField( + auto_created=True, + verbose_name="ID", + serialize=False, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "label", + ralph.lib.mixins.fields.NullableCharField( + verbose_name="name", max_length=255, blank=True, null=True + ), + ), + ( + "mac", + ralph.lib.mixins.fields.NullableCharField( + verbose_name="MAC address", + validators=[ + django.core.validators.RegexValidator( + message="'%(value)s' is not a valid MAC address.", + regex=re.compile( + "^\\s*([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\\s*$", + 32, + ), + ) + ], + unique=True, + max_length=24, + blank=True, + null=True, + ), + ), + ( + "speed", + models.PositiveIntegerField( + verbose_name="speed", + default=11, + choices=[ + (1, "10 Mbps"), + (2, "100 Mbps"), + (3, "1 Gbps"), + (4, "10 Gbps"), + (5, "40 Gbps"), + (6, "100 Gbps"), + (11, "unknown speed"), + ], + ), + ), + ( + "base_object", + models.ForeignKey( + related_name="ethernet", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "model", + models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + verbose_name="model", + to="assets.ComponentModel", + default=None, + blank=True, + null=True, + ), + ), ], options={ - 'verbose_name': 'ethernet', - 'verbose_name_plural': 'ethernets', - 'ordering': ('base_object', 'mac'), + "verbose_name": "ethernet", + "verbose_name_plural": "ethernets", + "ordering": ("base_object", "mac"), }, ), migrations.AddField( - model_name='genericcomponent', - name='created', - field=models.DateTimeField(verbose_name='date created', default=datetime.datetime(2016, 6, 6, 14, 7, 47, 639689), auto_now_add=True), + model_name="genericcomponent", + name="created", + field=models.DateTimeField( + verbose_name="date created", + default=datetime.datetime(2016, 6, 6, 14, 7, 47, 639689), + auto_now_add=True, + ), preserve_default=False, ), migrations.AddField( - model_name='genericcomponent', - name='modified', - field=models.DateTimeField(verbose_name='last modified', default=datetime.datetime(2016, 6, 6, 14, 7, 51, 223597), auto_now=True), + model_name="genericcomponent", + name="modified", + field=models.DateTimeField( + verbose_name="last modified", + default=datetime.datetime(2016, 6, 6, 14, 7, 51, 223597), + auto_now=True, + ), preserve_default=False, ), migrations.AlterField( - model_name='assetlasthostname', - name='postfix', + model_name="assetlasthostname", + name="postfix", field=models.CharField(db_index=True, max_length=30), ), migrations.AlterField( - model_name='assetlasthostname', - name='prefix', + model_name="assetlasthostname", + name="prefix", field=models.CharField(db_index=True, max_length=30), ), migrations.AddField( - model_name='configurationclass', - name='module', - field=models.ForeignKey(related_name='configuration_classes', to='assets.ConfigurationModule', on_delete=django.db.models.deletion.CASCADE), + model_name="configurationclass", + name="module", + field=models.ForeignKey( + related_name="configuration_classes", + to="assets.ConfigurationModule", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='baseobject', - name='configuration_path', - field=models.ForeignKey(to='assets.ConfigurationClass', verbose_name='configuration path', help_text='path to configuration for this object, for example path to puppet class', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="baseobject", + name="configuration_path", + field=models.ForeignKey( + to="assets.ConfigurationClass", + verbose_name="configuration path", + help_text="path to configuration for this object, for example path to puppet class", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterUniqueTogether( - name='configurationmodule', - unique_together=set([('parent', 'name')]), + name="configurationmodule", + unique_together=set([("parent", "name")]), ), migrations.AlterUniqueTogether( - name='configurationclass', - unique_together=set([('module', 'class_name')]), + name="configurationclass", + unique_together=set([("module", "class_name")]), ), ] diff --git a/src/ralph/assets/migrations/0013_auto_20160615_2140.py b/src/ralph/assets/migrations/0013_auto_20160615_2140.py index b723c1f54c..3270768010 100644 --- a/src/ralph/assets/migrations/0013_auto_20160615_2140.py +++ b/src/ralph/assets/migrations/0013_auto_20160615_2140.py @@ -6,20 +6,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0012_auto_20160606_1409'), + ("assets", "0012_auto_20160606_1409"), ] operations = [ migrations.AlterField( - model_name='ethernet', - name='base_object', - field=models.ForeignKey(related_name='ethernet_set', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE), + model_name="ethernet", + name="base_object", + field=models.ForeignKey( + related_name="ethernet_set", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterField( - model_name='genericcomponent', - name='base_object', - field=models.ForeignKey(related_name='genericcomponent_set', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE), + model_name="genericcomponent", + name="base_object", + field=models.ForeignKey( + related_name="genericcomponent_set", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/assets/migrations/0014_memory.py b/src/ralph/assets/migrations/0014_memory.py index 22eafb5edc..4d39e151a0 100644 --- a/src/ralph/assets/migrations/0014_memory.py +++ b/src/ralph/assets/migrations/0014_memory.py @@ -6,28 +6,70 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0013_auto_20160615_2140'), + ("assets", "0013_auto_20160615_2140"), ] operations = [ migrations.CreateModel( - name='Memory', + name="Memory", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), - ('label', models.CharField(max_length=255, verbose_name='name')), - ('size', models.PositiveIntegerField(verbose_name='size (MiB)')), - ('speed', models.PositiveIntegerField(null=True, blank=True, verbose_name='speed (MHz)')), - ('slot_no', models.PositiveIntegerField(null=True, blank=True, verbose_name='slot number')), - ('base_object', models.ForeignKey(related_name='memory_set', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('model', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='assets.ComponentModel', blank=True, default=None, null=True, verbose_name='model')), + ( + "id", + models.AutoField( + serialize=False, + auto_created=True, + primary_key=True, + verbose_name="ID", + ), + ), + ( + "created", + models.DateTimeField( + auto_now_add=True, verbose_name="date created" + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), + ("label", models.CharField(max_length=255, verbose_name="name")), + ("size", models.PositiveIntegerField(verbose_name="size (MiB)")), + ( + "speed", + models.PositiveIntegerField( + null=True, blank=True, verbose_name="speed (MHz)" + ), + ), + ( + "slot_no", + models.PositiveIntegerField( + null=True, blank=True, verbose_name="slot number" + ), + ), + ( + "base_object", + models.ForeignKey( + related_name="memory_set", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "model", + models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + to="assets.ComponentModel", + blank=True, + default=None, + null=True, + verbose_name="model", + ), + ), ], options={ - 'verbose_name_plural': 'memories', - 'verbose_name': 'memory', + "verbose_name_plural": "memories", + "verbose_name": "memory", }, ), ] diff --git a/src/ralph/assets/migrations/0015_auto_20160701_0952.py b/src/ralph/assets/migrations/0015_auto_20160701_0952.py index e08988f301..06a6de74c2 100644 --- a/src/ralph/assets/migrations/0015_auto_20160701_0952.py +++ b/src/ralph/assets/migrations/0015_auto_20160701_0952.py @@ -6,47 +6,56 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0014_memory'), + ("assets", "0014_memory"), ] operations = [ migrations.AlterModelOptions( - name='memory', - options={'verbose_name': 'memory', 'verbose_name_plural': 'memory'}, + name="memory", + options={"verbose_name": "memory", "verbose_name_plural": "memory"}, ), migrations.RemoveField( - model_name='memory', - name='label', + model_name="memory", + name="label", ), migrations.RemoveField( - model_name='memory', - name='slot_no', + model_name="memory", + name="slot_no", ), migrations.AddField( - model_name='ethernet', - name='firmware_version', - field=models.CharField(max_length=255, verbose_name='firmware version', blank=True, null=True), + model_name="ethernet", + name="firmware_version", + field=models.CharField( + max_length=255, verbose_name="firmware version", blank=True, null=True + ), ), migrations.AddField( - model_name='ethernet', - name='model_name', - field=models.CharField(max_length=255, verbose_name='model name', blank=True, null=True), + model_name="ethernet", + name="model_name", + field=models.CharField( + max_length=255, verbose_name="model name", blank=True, null=True + ), ), migrations.AddField( - model_name='genericcomponent', - name='model_name', - field=models.CharField(max_length=255, verbose_name='model name', blank=True, null=True), + model_name="genericcomponent", + name="model_name", + field=models.CharField( + max_length=255, verbose_name="model name", blank=True, null=True + ), ), migrations.AddField( - model_name='memory', - name='model_name', - field=models.CharField(max_length=255, verbose_name='model name', blank=True, null=True), + model_name="memory", + name="model_name", + field=models.CharField( + max_length=255, verbose_name="model name", blank=True, null=True + ), ), migrations.AlterField( - model_name='ethernet', - name='label', - field=ralph.lib.mixins.fields.NullableCharField(max_length=255, verbose_name='label', blank=True, null=True), + model_name="ethernet", + name="label", + field=ralph.lib.mixins.fields.NullableCharField( + max_length=255, verbose_name="label", blank=True, null=True + ), ), ] diff --git a/src/ralph/assets/migrations/0016_fibrechannelcard.py b/src/ralph/assets/migrations/0016_fibrechannelcard.py index b37f19a1f0..fe96d7b954 100644 --- a/src/ralph/assets/migrations/0016_fibrechannelcard.py +++ b/src/ralph/assets/migrations/0016_fibrechannelcard.py @@ -7,28 +7,98 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0015_auto_20160701_0952'), + ("assets", "0015_auto_20160701_0952"), ] operations = [ migrations.CreateModel( - name='FibreChannelCard', + name="FibreChannelCard", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('model_name', models.CharField(null=True, verbose_name='model name', blank=True, max_length=255)), - ('firmware_version', models.CharField(null=True, verbose_name='firmware version', blank=True, max_length=255)), - ('speed', models.PositiveIntegerField(choices=[(1, '1 Gbit'), (2, '2 Gbit'), (3, '4 Gbit'), (4, '8 Gbit'), (5, '16 Gbit'), (6, '32 Gbit'), (11, 'unknown speed')], verbose_name='speed', default=11)), - ('wwn', ralph.lib.mixins.fields.NullableCharField(verbose_name='WWN', blank=True, default=None, max_length=255, null=True, unique=True)), - ('base_object', models.ForeignKey(to='assets.BaseObject', related_name='fibrechannelcard_set', on_delete=django.db.models.deletion.CASCADE)), - ('model', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='model', blank=True, default=None, to='assets.ComponentModel', null=True)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "model_name", + models.CharField( + null=True, verbose_name="model name", blank=True, max_length=255 + ), + ), + ( + "firmware_version", + models.CharField( + null=True, + verbose_name="firmware version", + blank=True, + max_length=255, + ), + ), + ( + "speed", + models.PositiveIntegerField( + choices=[ + (1, "1 Gbit"), + (2, "2 Gbit"), + (3, "4 Gbit"), + (4, "8 Gbit"), + (5, "16 Gbit"), + (6, "32 Gbit"), + (11, "unknown speed"), + ], + verbose_name="speed", + default=11, + ), + ), + ( + "wwn", + ralph.lib.mixins.fields.NullableCharField( + verbose_name="WWN", + blank=True, + default=None, + max_length=255, + null=True, + unique=True, + ), + ), + ( + "base_object", + models.ForeignKey( + to="assets.BaseObject", + related_name="fibrechannelcard_set", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "model", + models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + verbose_name="model", + blank=True, + default=None, + to="assets.ComponentModel", + null=True, + ), + ), ], options={ - 'verbose_name': 'fibre channel card', - 'verbose_name_plural': 'fibre channel cards', + "verbose_name": "fibre channel card", + "verbose_name_plural": "fibre channel cards", }, ), ] diff --git a/src/ralph/assets/migrations/0017_processor.py b/src/ralph/assets/migrations/0017_processor.py index b7f9c6b756..f58fd517a6 100644 --- a/src/ralph/assets/migrations/0017_processor.py +++ b/src/ralph/assets/migrations/0017_processor.py @@ -6,27 +6,69 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0016_fibrechannelcard'), + ("assets", "0016_fibrechannelcard"), ] operations = [ migrations.CreateModel( - name='Processor', + name="Processor", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('model_name', models.CharField(null=True, verbose_name='model name', blank=True, max_length=255)), - ('speed', models.PositiveIntegerField(null=True, verbose_name='speed (MHz)', blank=True)), - ('cores', models.PositiveIntegerField(null=True, blank=True)), - ('base_object', models.ForeignKey(related_name='processor_set', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('model', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, null=True, verbose_name='model', to='assets.ComponentModel', default=None)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + primary_key=True, + serialize=False, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "model_name", + models.CharField( + null=True, verbose_name="model name", blank=True, max_length=255 + ), + ), + ( + "speed", + models.PositiveIntegerField( + null=True, verbose_name="speed (MHz)", blank=True + ), + ), + ("cores", models.PositiveIntegerField(null=True, blank=True)), + ( + "base_object", + models.ForeignKey( + related_name="processor_set", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "model", + models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + blank=True, + null=True, + verbose_name="model", + to="assets.ComponentModel", + default=None, + ), + ), ], options={ - 'verbose_name': 'processor', - 'verbose_name_plural': 'processors', + "verbose_name": "processor", + "verbose_name_plural": "processors", }, ), ] diff --git a/src/ralph/assets/migrations/0018_disk.py b/src/ralph/assets/migrations/0018_disk.py index d7b42f0296..37a0470307 100644 --- a/src/ralph/assets/migrations/0018_disk.py +++ b/src/ralph/assets/migrations/0018_disk.py @@ -6,29 +6,87 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0017_processor'), + ("assets", "0017_processor"), ] operations = [ migrations.CreateModel( - name='Disk', + name="Disk", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('model_name', models.CharField(verbose_name='model name', blank=True, null=True, max_length=255)), - ('size', models.PositiveIntegerField(verbose_name='size (GiB)')), - ('serial_number', models.CharField(verbose_name='serial number', blank=True, null=True, max_length=255)), - ('slot', models.PositiveIntegerField(verbose_name='slot number', blank=True, null=True)), - ('firmware_version', models.CharField(verbose_name='firmware version', blank=True, null=True, max_length=255)), - ('base_object', models.ForeignKey(to='assets.BaseObject', related_name='disk_set', on_delete=django.db.models.deletion.CASCADE)), - ('model', models.ForeignKey(verbose_name='model', to='assets.ComponentModel', null=True, default=None, blank=True, on_delete=django.db.models.deletion.SET_NULL)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "model_name", + models.CharField( + verbose_name="model name", blank=True, null=True, max_length=255 + ), + ), + ("size", models.PositiveIntegerField(verbose_name="size (GiB)")), + ( + "serial_number", + models.CharField( + verbose_name="serial number", + blank=True, + null=True, + max_length=255, + ), + ), + ( + "slot", + models.PositiveIntegerField( + verbose_name="slot number", blank=True, null=True + ), + ), + ( + "firmware_version", + models.CharField( + verbose_name="firmware version", + blank=True, + null=True, + max_length=255, + ), + ), + ( + "base_object", + models.ForeignKey( + to="assets.BaseObject", + related_name="disk_set", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "model", + models.ForeignKey( + verbose_name="model", + to="assets.ComponentModel", + null=True, + default=None, + blank=True, + on_delete=django.db.models.deletion.SET_NULL, + ), + ), ], options={ - 'verbose_name': 'disk', - 'verbose_name_plural': 'disks', + "verbose_name": "disk", + "verbose_name_plural": "disks", }, ), ] diff --git a/src/ralph/assets/migrations/0019_auto_20160719_1443.py b/src/ralph/assets/migrations/0019_auto_20160719_1443.py index 4852bd0ac9..d51ba0bd13 100644 --- a/src/ralph/assets/migrations/0019_auto_20160719_1443.py +++ b/src/ralph/assets/migrations/0019_auto_20160719_1443.py @@ -1,22 +1,34 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import re import ralph.lib.mixins.fields import django.core.validators class Migration(migrations.Migration): - dependencies = [ - ('assets', '0018_disk'), + ("assets", "0018_disk"), ] operations = [ migrations.AlterField( - model_name='ethernet', - name='mac', - field=ralph.lib.mixins.fields.MACAddressField(blank=True, null=True, verbose_name='MAC address', unique=True, validators=[django.core.validators.RegexValidator(regex=re.compile('^\\s*([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\\s*$', 32), message="'%(value)s' is not a valid MAC address.")]), + model_name="ethernet", + name="mac", + field=ralph.lib.mixins.fields.MACAddressField( + blank=True, + null=True, + verbose_name="MAC address", + unique=True, + validators=[ + django.core.validators.RegexValidator( + regex=re.compile( + "^\\s*([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\\s*$", 32 + ), + message="'%(value)s' is not a valid MAC address.", + ) + ], + ), ), ] diff --git a/src/ralph/assets/migrations/0020_auto_20160803_0712.py b/src/ralph/assets/migrations/0020_auto_20160803_0712.py index 6e349de35a..e302c07950 100644 --- a/src/ralph/assets/migrations/0020_auto_20160803_0712.py +++ b/src/ralph/assets/migrations/0020_auto_20160803_0712.py @@ -1,32 +1,32 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations from ralph.assets._migration_helpers import InheritFromBaseObject class Migration(migrations.Migration): - dependencies = [ - ('assets', '0019_auto_20160719_1443'), - ('data_importer', '0004_auto_20160728_1046'), + ("assets", "0019_auto_20160719_1443"), + ("data_importer", "0004_auto_20160728_1046"), ] operations = [ InheritFromBaseObject( - 'assets', 'ConfigurationClass', + "assets", + "ConfigurationClass", rewrite_fields={ - 'created': 'created', - 'modified': 'modified', - } + "created": "created", + "modified": "modified", + }, ), migrations.RemoveField( - model_name='configurationclass', - name='created', + model_name="configurationclass", + name="created", ), migrations.RemoveField( - model_name='configurationclass', - name='modified', + model_name="configurationclass", + name="modified", ), ] diff --git a/src/ralph/assets/migrations/0021_auto_20160810_1410.py b/src/ralph/assets/migrations/0021_auto_20160810_1410.py index 5c390f869c..d0ba3f549e 100644 --- a/src/ralph/assets/migrations/0021_auto_20160810_1410.py +++ b/src/ralph/assets/migrations/0021_auto_20160810_1410.py @@ -5,15 +5,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0020_auto_20160803_0712'), + ("assets", "0020_auto_20160803_0712"), ] operations = [ migrations.AlterField( - model_name='configurationclass', - name='path', - field=models.CharField(default='', verbose_name='path', help_text='path is constructed from name of module and name of class', blank=True, max_length=511, editable=False), + model_name="configurationclass", + name="path", + field=models.CharField( + default="", + verbose_name="path", + help_text="path is constructed from name of module and name of class", + blank=True, + max_length=511, + editable=False, + ), ), ] diff --git a/src/ralph/assets/migrations/0022_auto_20160823_0921.py b/src/ralph/assets/migrations/0022_auto_20160823_0921.py index f05b1d54bc..185c049d96 100644 --- a/src/ralph/assets/migrations/0022_auto_20160823_0921.py +++ b/src/ralph/assets/migrations/0022_auto_20160823_0921.py @@ -6,25 +6,38 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0021_auto_20160810_1410'), + ("assets", "0021_auto_20160810_1410"), ] operations = [ migrations.AlterField( - model_name='asset', - name='invoice_no', - field=models.CharField(null=True, blank=True, verbose_name='invoice number', max_length=128, db_index=True), + model_name="asset", + name="invoice_no", + field=models.CharField( + null=True, + blank=True, + verbose_name="invoice number", + max_length=128, + db_index=True, + ), ), migrations.AlterField( - model_name='asset', - name='niw', - field=ralph.lib.mixins.fields.NullableCharField(null=True, blank=True, verbose_name='inventory number', default=None, max_length=200), + model_name="asset", + name="niw", + field=ralph.lib.mixins.fields.NullableCharField( + null=True, + blank=True, + verbose_name="inventory number", + default=None, + max_length=200, + ), ), migrations.AlterField( - model_name='asset', - name='order_no', - field=models.CharField(null=True, blank=True, max_length=50, verbose_name='order number'), + model_name="asset", + name="order_no", + field=models.CharField( + null=True, blank=True, max_length=50, verbose_name="order number" + ), ), ] diff --git a/src/ralph/assets/migrations/0023_category_allow_deployment.py b/src/ralph/assets/migrations/0023_category_allow_deployment.py index 42b2c03223..2f5d72e4c4 100644 --- a/src/ralph/assets/migrations/0023_category_allow_deployment.py +++ b/src/ralph/assets/migrations/0023_category_allow_deployment.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0022_auto_20160823_0921'), + ("assets", "0022_auto_20160823_0921"), ] operations = [ migrations.AddField( - model_name='category', - name='allow_deployment', + model_name="category", + name="allow_deployment", field=models.BooleanField(default=False), ), ] diff --git a/src/ralph/assets/migrations/0024_auto_20170322_1148.py b/src/ralph/assets/migrations/0024_auto_20170322_1148.py index 7b4d7f73a0..b3b9313192 100644 --- a/src/ralph/assets/migrations/0024_auto_20170322_1148.py +++ b/src/ralph/assets/migrations/0024_auto_20170322_1148.py @@ -6,25 +6,41 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0023_category_allow_deployment'), + ("assets", "0023_category_allow_deployment"), ] operations = [ migrations.AlterField( - model_name='baseobject', - name='configuration_path', - field=models.ForeignKey(verbose_name='configuration path', blank=True, help_text='path to configuration for this object, for example path to puppet class', on_delete=django.db.models.deletion.PROTECT, null=True, to='assets.ConfigurationClass'), + model_name="baseobject", + name="configuration_path", + field=models.ForeignKey( + verbose_name="configuration path", + blank=True, + help_text="path to configuration for this object, for example path to puppet class", + on_delete=django.db.models.deletion.PROTECT, + null=True, + to="assets.ConfigurationClass", + ), ), migrations.AlterField( - model_name='baseobject', - name='parent', - field=models.ForeignKey(related_name='children', to='assets.BaseObject', blank=True, on_delete=django.db.models.deletion.SET_NULL, null=True), + model_name="baseobject", + name="parent", + field=models.ForeignKey( + related_name="children", + to="assets.BaseObject", + blank=True, + on_delete=django.db.models.deletion.SET_NULL, + null=True, + ), ), migrations.AlterField( - model_name='baseobject', - name='service_env', - field=models.ForeignKey(to='assets.ServiceEnvironment', on_delete=django.db.models.deletion.PROTECT, null=True), + model_name="baseobject", + name="service_env", + field=models.ForeignKey( + to="assets.ServiceEnvironment", + on_delete=django.db.models.deletion.PROTECT, + null=True, + ), ), ] diff --git a/src/ralph/assets/migrations/0025_auto_20170331_1341.py b/src/ralph/assets/migrations/0025_auto_20170331_1341.py index 43bef86d3f..a964be2987 100644 --- a/src/ralph/assets/migrations/0025_auto_20170331_1341.py +++ b/src/ralph/assets/migrations/0025_auto_20170331_1341.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0024_auto_20170322_1148'), + ("assets", "0024_auto_20170322_1148"), ] operations = [ migrations.AlterField( - model_name='asset', - name='model', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.AssetModel', related_name='assets'), + model_name="asset", + name="model", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="assets.AssetModel", + related_name="assets", + ), ), ] diff --git a/src/ralph/assets/migrations/0026_auto_20170510_0840.py b/src/ralph/assets/migrations/0026_auto_20170510_0840.py index 2944750548..291907b034 100644 --- a/src/ralph/assets/migrations/0026_auto_20170510_0840.py +++ b/src/ralph/assets/migrations/0026_auto_20170510_0840.py @@ -7,27 +7,43 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0025_auto_20170331_1341'), + ("assets", "0025_auto_20170331_1341"), ] operations = [ migrations.CreateModel( - name='ManufacturerKind', + name="ManufacturerKind", fields=[ - ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), - ('name', models.CharField(verbose_name='name', max_length=255, unique=True)), + ( + "id", + models.AutoField( + primary_key=True, + verbose_name="ID", + auto_created=True, + serialize=False, + ), + ), + ( + "name", + models.CharField(verbose_name="name", max_length=255, unique=True), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.AddField( - model_name='manufacturer', - name='manufacturer_kind', - field=models.ForeignKey(verbose_name='manufacturer kind', null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.ManufacturerKind', blank=True), + model_name="manufacturer", + name="manufacturer_kind", + field=models.ForeignKey( + verbose_name="manufacturer kind", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="assets.ManufacturerKind", + blank=True, + ), ), ] diff --git a/src/ralph/assets/migrations/0027_asset_buyout_date.py b/src/ralph/assets/migrations/0027_asset_buyout_date.py index a04051ac3b..55433bfee1 100644 --- a/src/ralph/assets/migrations/0027_asset_buyout_date.py +++ b/src/ralph/assets/migrations/0027_asset_buyout_date.py @@ -7,8 +7,7 @@ def get_depreciation_months(asset): return int( - (1 / (asset.depreciation_rate / 100) * 12) - if asset.depreciation_rate else 0 + (1 / (asset.depreciation_rate / 100) * 12) if asset.depreciation_rate else 0 ) @@ -24,22 +23,21 @@ def calculate_buyout_date(asset): def update_buyout_date(apps, schema_editor): - Asset = apps.get_model('assets', 'Asset') + Asset = apps.get_model("assets", "Asset") for asset in Asset.objects.filter(model__category__show_buyout_date=True): asset.buyout_date = calculate_buyout_date(asset) - asset.save(update_fields=['buyout_date']) + asset.save(update_fields=["buyout_date"]) class Migration(migrations.Migration): - dependencies = [ - ('assets', '0026_auto_20170510_0840'), + ("assets", "0026_auto_20170510_0840"), ] operations = [ migrations.AddField( - model_name='asset', - name='buyout_date', + model_name="asset", + name="buyout_date", field=models.DateField(blank=True, db_index=True, null=True), ), migrations.RunPython( diff --git a/src/ralph/assets/migrations/0028_auto_20180730_1135.py b/src/ralph/assets/migrations/0028_auto_20180730_1135.py index b414432167..0813afacae 100644 --- a/src/ralph/assets/migrations/0028_auto_20180730_1135.py +++ b/src/ralph/assets/migrations/0028_auto_20180730_1135.py @@ -6,38 +6,55 @@ def rewrite_business_segment_from_pc(apps, schema_editor): - Service = apps.get_model('assets', 'Service') - for service in Service.objects.filter(profit_center__business_segment__isnull=False): - print('Assigning {} to {}'.format(service.profit_center.business_segment.name, service.name)) + Service = apps.get_model("assets", "Service") + for service in Service.objects.filter( + profit_center__business_segment__isnull=False + ): + print( + "Assigning {} to {}".format( + service.profit_center.business_segment.name, service.name + ) + ) service.business_segment = service.profit_center.business_segment - service.save(update_fields=['business_segment']) + service.save(update_fields=["business_segment"]) def rewrite_business_segment_to_pc(apps, schema_editor): - Service = apps.get_model('assets', 'Service') - for service in Service.objects.filter(profit_center__isnull=False, business_segment__isnull=False): - print('Assigning {} to {}'.format(service.business_segment.name, service.profit_center.name)) + Service = apps.get_model("assets", "Service") + for service in Service.objects.filter( + profit_center__isnull=False, business_segment__isnull=False + ): + print( + "Assigning {} to {}".format( + service.business_segment.name, service.profit_center.name + ) + ) service.profit_center.business_segment = service.business_segment - service.profit_center.save(update_fields=['business_segment']) + service.profit_center.save(update_fields=["business_segment"]) class Migration(migrations.Migration): - dependencies = [ - ('assets', '0027_asset_buyout_date'), + ("assets", "0027_asset_buyout_date"), ] operations = [ migrations.AddField( - model_name='service', - name='business_segment', - field=models.ForeignKey(blank=True, null=True, to='assets.BusinessSegment', on_delete=django.db.models.deletion.CASCADE), + model_name="service", + name="business_segment", + field=models.ForeignKey( + blank=True, + null=True, + to="assets.BusinessSegment", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.RunPython( - rewrite_business_segment_from_pc, reverse_code=rewrite_business_segment_to_pc + rewrite_business_segment_from_pc, + reverse_code=rewrite_business_segment_to_pc, ), migrations.RemoveField( - model_name='profitcenter', - name='business_segment', + model_name="profitcenter", + name="business_segment", ), ] diff --git a/src/ralph/assets/migrations/0029_asset_start_usage.py b/src/ralph/assets/migrations/0029_asset_start_usage.py index 89564e0e7f..c78b1be339 100644 --- a/src/ralph/assets/migrations/0029_asset_start_usage.py +++ b/src/ralph/assets/migrations/0029_asset_start_usage.py @@ -5,15 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0028_auto_20180730_1135'), + ("assets", "0028_auto_20180730_1135"), ] operations = [ migrations.AddField( - model_name='asset', - name='start_usage', - field=models.DateField(null=True, blank=True, help_text='Fill it if date of first usage is different then date of creation'), + model_name="asset", + name="start_usage", + field=models.DateField( + null=True, + blank=True, + help_text="Fill it if date of first usage is different then date of creation", + ), ), ] diff --git a/src/ralph/assets/migrations/0030_auto_20200528_1301.py b/src/ralph/assets/migrations/0030_auto_20200528_1301.py index 1c74c46516..00910f5be2 100644 --- a/src/ralph/assets/migrations/0030_auto_20200528_1301.py +++ b/src/ralph/assets/migrations/0030_auto_20200528_1301.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('assets', '0029_asset_start_usage'), + ("assets", "0029_asset_start_usage"), ] operations = [ migrations.AlterModelOptions( - name='serviceenvironment', - options={'ordering': ('service__name', 'environment__name')}, + name="serviceenvironment", + options={"ordering": ("service__name", "environment__name")}, ), ] diff --git a/src/ralph/assets/migrations/0031_auto_20200728_1326.py b/src/ralph/assets/migrations/0031_auto_20200728_1326.py index 29920805c6..94146e525d 100644 --- a/src/ralph/assets/migrations/0031_auto_20200728_1326.py +++ b/src/ralph/assets/migrations/0031_auto_20200728_1326.py @@ -6,15 +6,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0030_auto_20200528_1301'), + ("assets", "0030_auto_20200528_1301"), ] operations = [ migrations.AlterField( - model_name='baseobject', - name='service_env', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='assets.ServiceEnvironment'), + model_name="baseobject", + name="service_env", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="assets.ServiceEnvironment", + ), ), ] diff --git a/src/ralph/assets/migrations/0032_auto_20200909_1012.py b/src/ralph/assets/migrations/0032_auto_20200909_1012.py index 50b21acfe6..9242c63f2d 100644 --- a/src/ralph/assets/migrations/0032_auto_20200909_1012.py +++ b/src/ralph/assets/migrations/0032_auto_20200909_1012.py @@ -1,26 +1,227 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import djmoney.models.fields from decimal import Decimal class Migration(migrations.Migration): - dependencies = [ - ('assets', '0031_auto_20200728_1326'), + ("assets", "0031_auto_20200728_1326"), ] operations = [ migrations.AddField( - model_name='asset', - name='price_currency', - field=djmoney.models.fields.CurrencyField(max_length=3, default='XXX', editable=False, choices=[('XXX', '---'), ('AED', 'AED'), ('AFN', 'AFN'), ('ALL', 'ALL'), ('AMD', 'AMD'), ('ANG', 'ANG'), ('AOA', 'AOA'), ('ARS', 'ARS'), ('AUD', 'AUD'), ('AWG', 'AWG'), ('AZN', 'AZN'), ('BAM', 'BAM'), ('BBD', 'BBD'), ('BDT', 'BDT'), ('BGN', 'BGN'), ('BHD', 'BHD'), ('BIF', 'BIF'), ('BMD', 'BMD'), ('BND', 'BND'), ('BOB', 'BOB'), ('BOV', 'BOV'), ('BRL', 'BRL'), ('BSD', 'BSD'), ('BTN', 'BTN'), ('BWP', 'BWP'), ('BYN', 'BYN'), ('BYR', 'BYR'), ('BZD', 'BZD'), ('CAD', 'CAD'), ('CDF', 'CDF'), ('CHE', 'CHE'), ('CHF', 'CHF'), ('CHW', 'CHW'), ('CLF', 'CLF'), ('CLP', 'CLP'), ('CNY', 'CNY'), ('COP', 'COP'), ('COU', 'COU'), ('CRC', 'CRC'), ('CUC', 'CUC'), ('CUP', 'CUP'), ('CVE', 'CVE'), ('CZK', 'CZK'), ('DJF', 'DJF'), ('DKK', 'DKK'), ('DOP', 'DOP'), ('DZD', 'DZD'), ('EGP', 'EGP'), ('ERN', 'ERN'), ('ETB', 'ETB'), ('EUR', 'EUR'), ('FJD', 'FJD'), ('FKP', 'FKP'), ('GBP', 'GBP'), ('GEL', 'GEL'), ('GHS', 'GHS'), ('GIP', 'GIP'), ('GMD', 'GMD'), ('GNF', 'GNF'), ('GTQ', 'GTQ'), ('GYD', 'GYD'), ('HKD', 'HKD'), ('HNL', 'HNL'), ('HRK', 'HRK'), ('HTG', 'HTG'), ('HUF', 'HUF'), ('IDR', 'IDR'), ('ILS', 'ILS'), ('IMP', 'IMP'), ('INR', 'INR'), ('IQD', 'IQD'), ('IRR', 'IRR'), ('ISK', 'ISK'), ('JMD', 'JMD'), ('JOD', 'JOD'), ('JPY', 'JPY'), ('KES', 'KES'), ('KGS', 'KGS'), ('KHR', 'KHR'), ('KMF', 'KMF'), ('KPW', 'KPW'), ('KRW', 'KRW'), ('KWD', 'KWD'), ('KYD', 'KYD'), ('KZT', 'KZT'), ('LAK', 'LAK'), ('LBP', 'LBP'), ('LKR', 'LKR'), ('LRD', 'LRD'), ('LSL', 'LSL'), ('LTL', 'LTL'), ('LVL', 'LVL'), ('LYD', 'LYD'), ('MAD', 'MAD'), ('MDL', 'MDL'), ('MGA', 'MGA'), ('MKD', 'MKD'), ('MMK', 'MMK'), ('MNT', 'MNT'), ('MOP', 'MOP'), ('MRO', 'MRO'), ('MUR', 'MUR'), ('MVR', 'MVR'), ('MWK', 'MWK'), ('MXN', 'MXN'), ('MXV', 'MXV'), ('MYR', 'MYR'), ('MZN', 'MZN'), ('NAD', 'NAD'), ('NGN', 'NGN'), ('NIO', 'NIO'), ('NOK', 'NOK'), ('NPR', 'NPR'), ('NZD', 'NZD'), ('OMR', 'OMR'), ('PAB', 'PAB'), ('PEN', 'PEN'), ('PGK', 'PGK'), ('PHP', 'PHP'), ('PKR', 'PKR'), ('PLN', 'PLN'), ('PYG', 'PYG'), ('QAR', 'QAR'), ('RON', 'RON'), ('RSD', 'RSD'), ('RUB', 'RUB'), ('RWF', 'RWF'), ('SAR', 'SAR'), ('SBD', 'SBD'), ('SCR', 'SCR'), ('SDG', 'SDG'), ('SEK', 'SEK'), ('SGD', 'SGD'), ('SHP', 'SHP'), ('SLL', 'SLL'), ('SOS', 'SOS'), ('SRD', 'SRD'), ('SSP', 'SSP'), ('STD', 'STD'), ('SVC', 'SVC'), ('SYP', 'SYP'), ('SZL', 'SZL'), ('THB', 'THB'), ('TJS', 'TJS'), ('TMM', 'TMM'), ('TMT', 'TMT'), ('TND', 'TND'), ('TOP', 'TOP'), ('TRY', 'TRY'), ('TTD', 'TTD'), ('TVD', 'TVD'), ('TWD', 'TWD'), ('TZS', 'TZS'), ('UAH', 'UAH'), ('UGX', 'UGX'), ('USD', 'USD'), ('USN', 'USN'), ('UYI', 'UYI'), ('UYU', 'UYU'), ('UZS', 'UZS'), ('VEF', 'VEF'), ('VND', 'VND'), ('VUV', 'VUV'), ('WST', 'WST'), ('XAF', 'XAF'), ('XAG', 'XAG'), ('XAU', 'XAU'), ('XBA', 'XBA'), ('XBB', 'XBB'), ('XBC', 'XBC'), ('XBD', 'XBD'), ('XCD', 'XCD'), ('XDR', 'XDR'), ('XFO', 'XFO'), ('XFU', 'XFU'), ('XOF', 'XOF'), ('XPD', 'XPD'), ('XPF', 'XPF'), ('XPT', 'XPT'), ('XSU', 'XSU'), ('XTS', 'XTS'), ('XUA', 'XUA'), ('XYZ', 'XYZ'), ('YER', 'YER'), ('ZAR', 'ZAR'), ('ZMK', 'ZMK'), ('ZMW', 'ZMW'), ('ZWD', 'ZWD'), ('ZWL', 'ZWL'), ('ZWN', 'ZWN')]), + model_name="asset", + name="price_currency", + field=djmoney.models.fields.CurrencyField( + max_length=3, + default="XXX", + editable=False, + choices=[ + ("XXX", "---"), + ("AED", "AED"), + ("AFN", "AFN"), + ("ALL", "ALL"), + ("AMD", "AMD"), + ("ANG", "ANG"), + ("AOA", "AOA"), + ("ARS", "ARS"), + ("AUD", "AUD"), + ("AWG", "AWG"), + ("AZN", "AZN"), + ("BAM", "BAM"), + ("BBD", "BBD"), + ("BDT", "BDT"), + ("BGN", "BGN"), + ("BHD", "BHD"), + ("BIF", "BIF"), + ("BMD", "BMD"), + ("BND", "BND"), + ("BOB", "BOB"), + ("BOV", "BOV"), + ("BRL", "BRL"), + ("BSD", "BSD"), + ("BTN", "BTN"), + ("BWP", "BWP"), + ("BYN", "BYN"), + ("BYR", "BYR"), + ("BZD", "BZD"), + ("CAD", "CAD"), + ("CDF", "CDF"), + ("CHE", "CHE"), + ("CHF", "CHF"), + ("CHW", "CHW"), + ("CLF", "CLF"), + ("CLP", "CLP"), + ("CNY", "CNY"), + ("COP", "COP"), + ("COU", "COU"), + ("CRC", "CRC"), + ("CUC", "CUC"), + ("CUP", "CUP"), + ("CVE", "CVE"), + ("CZK", "CZK"), + ("DJF", "DJF"), + ("DKK", "DKK"), + ("DOP", "DOP"), + ("DZD", "DZD"), + ("EGP", "EGP"), + ("ERN", "ERN"), + ("ETB", "ETB"), + ("EUR", "EUR"), + ("FJD", "FJD"), + ("FKP", "FKP"), + ("GBP", "GBP"), + ("GEL", "GEL"), + ("GHS", "GHS"), + ("GIP", "GIP"), + ("GMD", "GMD"), + ("GNF", "GNF"), + ("GTQ", "GTQ"), + ("GYD", "GYD"), + ("HKD", "HKD"), + ("HNL", "HNL"), + ("HRK", "HRK"), + ("HTG", "HTG"), + ("HUF", "HUF"), + ("IDR", "IDR"), + ("ILS", "ILS"), + ("IMP", "IMP"), + ("INR", "INR"), + ("IQD", "IQD"), + ("IRR", "IRR"), + ("ISK", "ISK"), + ("JMD", "JMD"), + ("JOD", "JOD"), + ("JPY", "JPY"), + ("KES", "KES"), + ("KGS", "KGS"), + ("KHR", "KHR"), + ("KMF", "KMF"), + ("KPW", "KPW"), + ("KRW", "KRW"), + ("KWD", "KWD"), + ("KYD", "KYD"), + ("KZT", "KZT"), + ("LAK", "LAK"), + ("LBP", "LBP"), + ("LKR", "LKR"), + ("LRD", "LRD"), + ("LSL", "LSL"), + ("LTL", "LTL"), + ("LVL", "LVL"), + ("LYD", "LYD"), + ("MAD", "MAD"), + ("MDL", "MDL"), + ("MGA", "MGA"), + ("MKD", "MKD"), + ("MMK", "MMK"), + ("MNT", "MNT"), + ("MOP", "MOP"), + ("MRO", "MRO"), + ("MUR", "MUR"), + ("MVR", "MVR"), + ("MWK", "MWK"), + ("MXN", "MXN"), + ("MXV", "MXV"), + ("MYR", "MYR"), + ("MZN", "MZN"), + ("NAD", "NAD"), + ("NGN", "NGN"), + ("NIO", "NIO"), + ("NOK", "NOK"), + ("NPR", "NPR"), + ("NZD", "NZD"), + ("OMR", "OMR"), + ("PAB", "PAB"), + ("PEN", "PEN"), + ("PGK", "PGK"), + ("PHP", "PHP"), + ("PKR", "PKR"), + ("PLN", "PLN"), + ("PYG", "PYG"), + ("QAR", "QAR"), + ("RON", "RON"), + ("RSD", "RSD"), + ("RUB", "RUB"), + ("RWF", "RWF"), + ("SAR", "SAR"), + ("SBD", "SBD"), + ("SCR", "SCR"), + ("SDG", "SDG"), + ("SEK", "SEK"), + ("SGD", "SGD"), + ("SHP", "SHP"), + ("SLL", "SLL"), + ("SOS", "SOS"), + ("SRD", "SRD"), + ("SSP", "SSP"), + ("STD", "STD"), + ("SVC", "SVC"), + ("SYP", "SYP"), + ("SZL", "SZL"), + ("THB", "THB"), + ("TJS", "TJS"), + ("TMM", "TMM"), + ("TMT", "TMT"), + ("TND", "TND"), + ("TOP", "TOP"), + ("TRY", "TRY"), + ("TTD", "TTD"), + ("TVD", "TVD"), + ("TWD", "TWD"), + ("TZS", "TZS"), + ("UAH", "UAH"), + ("UGX", "UGX"), + ("USD", "USD"), + ("USN", "USN"), + ("UYI", "UYI"), + ("UYU", "UYU"), + ("UZS", "UZS"), + ("VEF", "VEF"), + ("VND", "VND"), + ("VUV", "VUV"), + ("WST", "WST"), + ("XAF", "XAF"), + ("XAG", "XAG"), + ("XAU", "XAU"), + ("XBA", "XBA"), + ("XBB", "XBB"), + ("XBC", "XBC"), + ("XBD", "XBD"), + ("XCD", "XCD"), + ("XDR", "XDR"), + ("XFO", "XFO"), + ("XFU", "XFU"), + ("XOF", "XOF"), + ("XPD", "XPD"), + ("XPF", "XPF"), + ("XPT", "XPT"), + ("XSU", "XSU"), + ("XTS", "XTS"), + ("XUA", "XUA"), + ("XYZ", "XYZ"), + ("YER", "YER"), + ("ZAR", "ZAR"), + ("ZMK", "ZMK"), + ("ZMW", "ZMW"), + ("ZWD", "ZWD"), + ("ZWL", "ZWL"), + ("ZWN", "ZWN"), + ], + ), ), migrations.AlterField( - model_name='asset', - name='price', - field=djmoney.models.fields.MoneyField(null=True, default=Decimal('0'), max_digits=15, decimal_places=2, default_currency='XXX'), + model_name="asset", + name="price", + field=djmoney.models.fields.MoneyField( + null=True, + default=Decimal("0"), + max_digits=15, + decimal_places=2, + default_currency="XXX", + ), ), ] diff --git a/src/ralph/assets/migrations/0033_auto_20211115_1125.py b/src/ralph/assets/migrations/0033_auto_20211115_1125.py index b125365d4f..7ca949a780 100644 --- a/src/ralph/assets/migrations/0033_auto_20211115_1125.py +++ b/src/ralph/assets/migrations/0033_auto_20211115_1125.py @@ -1,20 +1,25 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('assets', '0032_auto_20200909_1012'), + ("assets", "0032_auto_20200909_1012"), ] operations = [ migrations.AlterField( - model_name='asset', - name='hostname', - field=ralph.lib.mixins.fields.NullableCharFieldWithAutoStrip(verbose_name='hostname', max_length=255, blank=True, null=True, default=None), + model_name="asset", + name="hostname", + field=ralph.lib.mixins.fields.NullableCharFieldWithAutoStrip( + verbose_name="hostname", + max_length=255, + blank=True, + null=True, + default=None, + ), ), ] diff --git a/src/ralph/assets/migrations/0034_auto_20240304_1511.py b/src/ralph/assets/migrations/0034_auto_20240304_1511.py index 4a0e2241fd..c30ebd32f4 100644 --- a/src/ralph/assets/migrations/0034_auto_20240304_1511.py +++ b/src/ralph/assets/migrations/0034_auto_20240304_1511.py @@ -5,20 +5,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0033_auto_20211115_1125'), + ("assets", "0033_auto_20211115_1125"), ] operations = [ migrations.AddField( - model_name='processor', - name='logical_cores', + model_name="processor", + name="logical_cores", field=models.PositiveIntegerField(blank=True, null=True), ), migrations.AlterField( - model_name='processor', - name='cores', - field=models.PositiveIntegerField(verbose_name='physical cores', blank=True, null=True), + model_name="processor", + name="cores", + field=models.PositiveIntegerField( + verbose_name="physical cores", blank=True, null=True + ), ), ] diff --git a/src/ralph/assets/migrations/0035_auto_20240506_1633.py b/src/ralph/assets/migrations/0035_auto_20240506_1633.py index fb3d93e631..29a5f885ab 100644 --- a/src/ralph/assets/migrations/0035_auto_20240506_1633.py +++ b/src/ralph/assets/migrations/0035_auto_20240506_1633.py @@ -7,16 +7,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0034_auto_20240304_1511'), + ("assets", "0034_auto_20240304_1511"), ] operations = [ migrations.AlterModelManagers( - name='baseobject', + name="baseobject", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/assets/migrations/0036_auto_20240621_1200.py b/src/ralph/assets/migrations/0036_auto_20240621_1200.py index ce25430943..79b62e7016 100644 --- a/src/ralph/assets/migrations/0036_auto_20240621_1200.py +++ b/src/ralph/assets/migrations/0036_auto_20240621_1200.py @@ -6,40 +6,39 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0035_auto_20240506_1633'), + ("assets", "0035_auto_20240506_1633"), ] operations = [ migrations.AlterField( - model_name='category', - name='level', + model_name="category", + name="level", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='category', - name='lft', + model_name="category", + name="lft", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='category', - name='rght', + model_name="category", + name="rght", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='configurationmodule', - name='level', + model_name="configurationmodule", + name="level", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='configurationmodule', - name='lft', + model_name="configurationmodule", + name="lft", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='configurationmodule', - name='rght', + model_name="configurationmodule", + name="rght", field=models.PositiveIntegerField(editable=False), ), ] diff --git a/src/ralph/assets/migrations/0036_auto_20240904_1126.py b/src/ralph/assets/migrations/0036_auto_20240904_1126.py index 524f120c2d..49631a301e 100644 --- a/src/ralph/assets/migrations/0036_auto_20240904_1126.py +++ b/src/ralph/assets/migrations/0036_auto_20240904_1126.py @@ -8,20 +8,48 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0035_auto_20240506_1633'), + ("assets", "0035_auto_20240506_1633"), ] operations = [ migrations.AlterField( - model_name='asset', - name='barcode', - field=ralph.lib.mixins.fields.NullableCharField(blank=True, default=None, max_length=200, null=True, unique=True, validators=[django.core.validators.RegexValidator('\\s', 'No spaces allowed', code='no_spaces_allowed', inverse_match=True)], verbose_name='barcode'), + model_name="asset", + name="barcode", + field=ralph.lib.mixins.fields.NullableCharField( + blank=True, + default=None, + max_length=200, + null=True, + unique=True, + validators=[ + django.core.validators.RegexValidator( + "\\s", + "No spaces allowed", + code="no_spaces_allowed", + inverse_match=True, + ) + ], + verbose_name="barcode", + ), ), migrations.AlterField( - model_name='asset', - name='sn', - field=ralph.lib.mixins.fields.NullableCharField(blank=True, max_length=200, null=True, unique=True, validators=[django.core.validators.RegexValidator('\\s', 'No spaces allowed', code='no_spaces_allowed', inverse_match=True)], verbose_name='SN'), + model_name="asset", + name="sn", + field=ralph.lib.mixins.fields.NullableCharField( + blank=True, + max_length=200, + null=True, + unique=True, + validators=[ + django.core.validators.RegexValidator( + "\\s", + "No spaces allowed", + code="no_spaces_allowed", + inverse_match=True, + ) + ], + verbose_name="SN", + ), ), ] diff --git a/src/ralph/assets/migrations/0037_auto_20240621_1217.py b/src/ralph/assets/migrations/0037_auto_20240621_1217.py index 2edd75a306..e2343b55c5 100644 --- a/src/ralph/assets/migrations/0037_auto_20240621_1217.py +++ b/src/ralph/assets/migrations/0037_auto_20240621_1217.py @@ -5,28 +5,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0036_auto_20240621_1200'), + ("assets", "0036_auto_20240621_1200"), ] operations = [ migrations.AlterModelManagers( - name='asset', + name="asset", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='configurationclass', + name="configurationclass", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='serviceenvironment', + name="serviceenvironment", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/assets/migrations/0037_auto_20241008_1003.py b/src/ralph/assets/migrations/0037_auto_20241008_1003.py index bb896296c8..d60cc3a90a 100644 --- a/src/ralph/assets/migrations/0037_auto_20241008_1003.py +++ b/src/ralph/assets/migrations/0037_auto_20241008_1003.py @@ -6,15 +6,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0036_auto_20240904_1126'), + ("assets", "0036_auto_20240904_1126"), ] operations = [ migrations.AlterField( - model_name='ethernet', - name='speed', - field=models.PositiveIntegerField(choices=[(1, '10 Mbps'), (2, '100 Mbps'), (3, '1 Gbps'), (4, '10 Gbps'), (5, '40 Gbps'), (6, '100 Gbps'), (7, '25 Gbps'), (11, 'unknown speed')], default=11, verbose_name='speed'), + model_name="ethernet", + name="speed", + field=models.PositiveIntegerField( + choices=[ + (1, "10 Mbps"), + (2, "100 Mbps"), + (3, "1 Gbps"), + (4, "10 Gbps"), + (5, "40 Gbps"), + (6, "100 Gbps"), + (7, "25 Gbps"), + (11, "unknown speed"), + ], + default=11, + verbose_name="speed", + ), ), ] diff --git a/src/ralph/assets/migrations/0038_merge_20240916_1249.py b/src/ralph/assets/migrations/0038_merge_20240916_1249.py index a9840b47c0..b95ea3637f 100644 --- a/src/ralph/assets/migrations/0038_merge_20240916_1249.py +++ b/src/ralph/assets/migrations/0038_merge_20240916_1249.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0036_auto_20240904_1126'), - ('assets', '0037_auto_20240621_1217'), + ("assets", "0036_auto_20240904_1126"), + ("assets", "0037_auto_20240621_1217"), ] - operations = [ - ] + operations = [] diff --git a/src/ralph/assets/migrations/0039_merge_20241008_1243.py b/src/ralph/assets/migrations/0039_merge_20241008_1243.py index 36471da6b8..662fff8097 100644 --- a/src/ralph/assets/migrations/0039_merge_20241008_1243.py +++ b/src/ralph/assets/migrations/0039_merge_20241008_1243.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0037_auto_20241008_1003'), - ('assets', '0038_merge_20240916_1249'), + ("assets", "0037_auto_20241008_1003"), + ("assets", "0038_merge_20240916_1249"), ] - operations = [ - ] + operations = [] diff --git a/src/ralph/assets/models/__init__.py b/src/ralph/assets/models/__init__.py index 9e127f206b..a030a2f448 100644 --- a/src/ralph/assets/models/__init__.py +++ b/src/ralph/assets/models/__init__.py @@ -11,7 +11,7 @@ ManufacturerKind, ProfitCenter, Service, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.models.base import BaseObject from ralph.assets.models.choices import ( @@ -19,7 +19,7 @@ AssetSource, ComponentType, ModelVisualizationLayout, - ObjectModelType + ObjectModelType, ) from ralph.assets.models.components import ( ComponentModel, @@ -29,41 +29,38 @@ Ethernet, Memory, FibreChannelCard, - Processor -) -from ralph.assets.models.configuration import ( - ConfigurationClass, - ConfigurationModule + Processor, ) +from ralph.assets.models.configuration import ConfigurationClass, ConfigurationModule __all__ = [ - 'Asset', - 'AssetLastHostname', - 'AssetModel', - 'AssetHolder', - 'AssetPurpose', - 'AssetSource', - 'BudgetInfo', - 'BaseObject', - 'BusinessSegment', - 'Category', - 'Component', - 'ComponentModel', - 'ComponentType', - 'ConfigurationClass', - 'ConfigurationModule', - 'Disk', - 'Environment', - 'FibreChannelCard', - 'GenericComponent', - 'Manufacturer', - 'ManufacturerKind', - 'Memory', - 'ModelVisualizationLayout', - 'ObjectModelType', - 'ProfitCenter', - 'Processor', - 'Service', - 'ServiceEnvironment', - 'Ethernet', + "Asset", + "AssetLastHostname", + "AssetModel", + "AssetHolder", + "AssetPurpose", + "AssetSource", + "BudgetInfo", + "BaseObject", + "BusinessSegment", + "Category", + "Component", + "ComponentModel", + "ComponentType", + "ConfigurationClass", + "ConfigurationModule", + "Disk", + "Environment", + "FibreChannelCard", + "GenericComponent", + "Manufacturer", + "ManufacturerKind", + "Memory", + "ModelVisualizationLayout", + "ObjectModelType", + "ProfitCenter", + "Processor", + "Service", + "ServiceEnvironment", + "Ethernet", ] diff --git a/src/ralph/assets/models/assets.py b/src/ralph/assets/models/assets.py index e89e7972e8..a716d79e34 100644 --- a/src/ralph/assets/models/assets.py +++ b/src/ralph/assets/models/assets.py @@ -13,23 +13,14 @@ from ralph.accounts.models import Team from ralph.admin.autocomplete import AutocompleteTooltipMixin from ralph.assets.models.base import BaseObject -from ralph.assets.models.choices import ( - ModelVisualizationLayout, - ObjectModelType -) -from ralph.lib.custom_fields.models import ( - CustomFieldMeta, - WithCustomFieldsMixin -) -from ralph.lib.mixins.fields import ( - NullableCharField, - NullableCharFieldWithAutoStrip -) +from ralph.assets.models.choices import ModelVisualizationLayout, ObjectModelType +from ralph.lib.custom_fields.models import CustomFieldMeta, WithCustomFieldsMixin +from ralph.lib.mixins.fields import NullableCharField, NullableCharFieldWithAutoStrip from ralph.lib.mixins.models import ( AdminAbsoluteUrlMixin, NamedMixin, PriceMixin, - TimeStampMixin + TimeStampMixin, ) from ralph.lib.permissions.models import PermByFieldMixin, PermissionsBase @@ -37,10 +28,7 @@ class AssetHolder( - AdminAbsoluteUrlMixin, - NamedMixin.NonUnique, - TimeStampMixin, - models.Model + AdminAbsoluteUrlMixin, NamedMixin.NonUnique, TimeStampMixin, models.Model ): pass @@ -53,78 +41,65 @@ class ProfitCenter(AdminAbsoluteUrlMixin, NamedMixin, models.Model): description = models.TextField(blank=True) -class Environment( - AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model -): +class Environment(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): pass class Service( - PermByFieldMixin, - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model + PermByFieldMixin, AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model ): # Fixme: let's do service catalog replacement from that _allow_in_dashboard = True active = models.BooleanField(default=True) uid = NullableCharField(max_length=40, unique=True, blank=True, null=True) - profit_center = models.ForeignKey(ProfitCenter, null=True, blank=True, on_delete=models.CASCADE) + profit_center = models.ForeignKey( + ProfitCenter, null=True, blank=True, on_delete=models.CASCADE + ) business_segment = models.ForeignKey( - BusinessSegment, - null=True, - blank=True, - on_delete=models.CASCADE + BusinessSegment, null=True, blank=True, on_delete=models.CASCADE ) cost_center = models.CharField(max_length=100, blank=True) - environments = models.ManyToManyField( - 'Environment', through='ServiceEnvironment' - ) + environments = models.ManyToManyField("Environment", through="ServiceEnvironment") business_owners = models.ManyToManyField( settings.AUTH_USER_MODEL, - related_name='services_business_owner', + related_name="services_business_owner", blank=True, ) technical_owners = models.ManyToManyField( settings.AUTH_USER_MODEL, - related_name='services_technical_owner', + related_name="services_technical_owner", blank=True, ) support_team = models.ForeignKey( - Team, null=True, blank=True, related_name='services', on_delete=models.CASCADE + Team, null=True, blank=True, related_name="services", on_delete=models.CASCADE ) def __str__(self): - return '{}'.format(self.name) + return "{}".format(self.name) @classmethod def get_autocomplete_queryset(cls): return cls._default_manager.filter(active=True) -class ServiceEnvironment( - AdminAbsoluteUrlMixin, - AutocompleteTooltipMixin, - BaseObject -): +class ServiceEnvironment(AdminAbsoluteUrlMixin, AutocompleteTooltipMixin, BaseObject): _allow_in_dashboard = True service = models.ForeignKey(Service, on_delete=models.CASCADE) environment = models.ForeignKey(Environment, on_delete=models.CASCADE) autocomplete_tooltip_fields = [ - 'service__business_owners', - 'service__technical_owners', - 'service__support_team', + "service__business_owners", + "service__technical_owners", + "service__support_team", ] def __str__(self): - return '{} - {}'.format(self.service.name, self.environment.name) + return "{} - {}".format(self.service.name, self.environment.name) class Meta: - unique_together = ('service', 'environment') - ordering = ('service__name', 'environment__name') + unique_together = ("service", "environment") + ordering = ("service__name", "environment__name") @property def service_name(self): @@ -147,22 +122,18 @@ class ManufacturerKind(AdminAbsoluteUrlMixin, NamedMixin, models.Model): pass -class Manufacturer( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model -): +class Manufacturer(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): _allow_in_dashboard = True manufacturer_kind = models.ForeignKey( - ManufacturerKind, verbose_name=_('manufacturer kind'), + ManufacturerKind, + verbose_name=_("manufacturer kind"), null=True, blank=True, on_delete=models.SET_NULL, ) -AssetModelMeta = type('AssetModelMeta', (CustomFieldMeta, PermissionsBase), {}) +AssetModelMeta = type("AssetModelMeta", (CustomFieldMeta, PermissionsBase), {}) class AssetModel( @@ -172,19 +143,20 @@ class AssetModel( AdminAbsoluteUrlMixin, WithCustomFieldsMixin, models.Model, - metaclass=AssetModelMeta + metaclass=AssetModelMeta, ): # TODO: should type be determined based on category? _allow_in_dashboard = True type = models.PositiveIntegerField( - verbose_name=_('type'), choices=ObjectModelType(), + verbose_name=_("type"), + choices=ObjectModelType(), ) manufacturer = models.ForeignKey( Manufacturer, on_delete=models.PROTECT, blank=True, null=True ) category = TreeForeignKey( - 'Category', null=True, related_name='models', on_delete=models.CASCADE + "Category", null=True, related_name="models", on_delete=models.CASCADE ) power_consumption = models.PositiveIntegerField( verbose_name=_("Power consumption"), @@ -215,22 +187,18 @@ class AssetModel( has_parent = models.BooleanField(default=False) class Meta: - verbose_name = _('model') - verbose_name_plural = _('models') + verbose_name = _("model") + verbose_name_plural = _("models") def __str__(self): if self.category_id: - return '[{}] {} {}'.format( - self.category, self.manufacturer, self.name - ) + return "[{}] {} {}".format(self.category, self.manufacturer, self.name) else: - return '{} {}'.format( - self.manufacturer, self.name - ) + return "{} {}".format(self.manufacturer, self.name) def _get_layout_class(self, field): item = ModelVisualizationLayout.from_id(field) - return getattr(item, 'css_class', '') + return getattr(item, "css_class", "") def get_front_layout_class(self): return self._get_layout_class(self.visualization_layout_front) @@ -240,22 +208,18 @@ def get_back_layout_class(self): class Category( - AdminAbsoluteUrlMixin, - MPTTModel, - NamedMixin.NonUnique, - TimeStampMixin, - models.Model + AdminAbsoluteUrlMixin, MPTTModel, NamedMixin.NonUnique, TimeStampMixin, models.Model ): _allow_in_dashboard = True - code = models.CharField(max_length=4, blank=True, default='') + code = models.CharField(max_length=4, blank=True, default="") parent = TreeForeignKey( - 'self', + "self", null=True, blank=True, - related_name='children', + related_name="children", db_index=True, - on_delete=models.CASCADE + on_delete=models.CASCADE, ) imei_required = models.BooleanField(default=False) allow_deployment = models.BooleanField(default=False) @@ -265,7 +229,7 @@ class Category( decimal_places=2, default=settings.DEFAULT_DEPRECIATION_RATE, help_text=_( - 'This value is in percentage.' + "This value is in percentage." ' For example value: "100" means it depreciates during a year.' ' Value: "25" means it depreciates during 4 years, and so on... .' ), @@ -273,11 +237,11 @@ class Category( ) class Meta: - verbose_name = _('category') - verbose_name_plural = _('categories') + verbose_name = _("category") + verbose_name_plural = _("categories") class MPTTMeta: - order_insertion_by = ['name'] + order_insertion_by = ["name"] def __str__(self): return self.name @@ -299,10 +263,10 @@ class AssetLastHostname(models.Model): postfix = models.CharField(max_length=30, db_index=True) class Meta: - unique_together = ('prefix', 'postfix') + unique_together = ("prefix", "postfix") def formatted_hostname(self, fill=5): - return '{prefix}{counter:0{fill}}{postfix}'.format( + return "{prefix}{counter:0{fill}}{postfix}".format( prefix=self.prefix, counter=int(self.counter), fill=fill, @@ -311,14 +275,14 @@ def formatted_hostname(self, fill=5): @classmethod # TODO: select_for_update - def increment_hostname(cls, prefix, postfix=''): + def increment_hostname(cls, prefix, postfix=""): obj, created = cls.objects.get_or_create( prefix=prefix, postfix=postfix, ) if not created: # F() avoid race condition problem - obj.counter = models.F('counter') + 1 + obj.counter = models.F("counter") + 1 obj.save() return cls.objects.get(pk=obj.pk) else: @@ -347,15 +311,10 @@ def __str__(self): return self.formatted_hostname() -class BudgetInfo( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model -): +class BudgetInfo(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): class Meta: - verbose_name = _('Budget info') - verbose_name_plural = _('Budgets info') + verbose_name = _("Budget info") + verbose_name_plural = _("Budgets info") def __str__(self): return self.name @@ -363,7 +322,7 @@ def __str__(self): class Asset(AdminAbsoluteUrlMixin, PriceMixin, BaseObject): model = models.ForeignKey( - AssetModel, related_name='assets', on_delete=models.PROTECT + AssetModel, related_name="assets", on_delete=models.PROTECT ) # TODO: unify hostname for DCA, VirtualServer, Cluster and CloudHost # (use another model?) @@ -372,20 +331,22 @@ class Asset(AdminAbsoluteUrlMixin, PriceMixin, BaseObject): default=None, max_length=255, null=True, - verbose_name=_('hostname'), # TODO: unique + verbose_name=_("hostname"), # TODO: unique ) sn = NullableCharField( blank=True, max_length=200, null=True, - verbose_name=_('SN'), + verbose_name=_("SN"), unique=True, - validators=[RegexValidator( - r'\s', - _('No spaces allowed'), - inverse_match=True, - code="no_spaces_allowed", - )] + validators=[ + RegexValidator( + r"\s", + _("No spaces allowed"), + inverse_match=True, + code="no_spaces_allowed", + ) + ], ) barcode = NullableCharField( blank=True, @@ -393,31 +354,33 @@ class Asset(AdminAbsoluteUrlMixin, PriceMixin, BaseObject): max_length=200, null=True, unique=True, - verbose_name=_('barcode'), - validators=[RegexValidator( - r'\s', - _('No spaces allowed'), - inverse_match=True, - code="no_spaces_allowed", - )] + verbose_name=_("barcode"), + validators=[ + RegexValidator( + r"\s", + _("No spaces allowed"), + inverse_match=True, + code="no_spaces_allowed", + ) + ], ) niw = NullableCharField( blank=True, default=None, max_length=200, null=True, - verbose_name=_('inventory number'), + verbose_name=_("inventory number"), ) required_support = models.BooleanField(default=False) order_no = models.CharField( - verbose_name=_('order number'), + verbose_name=_("order number"), blank=True, max_length=50, null=True, ) invoice_no = models.CharField( - verbose_name=_('invoice number'), + verbose_name=_("invoice number"), blank=True, db_index=True, max_length=128, @@ -435,23 +398,21 @@ class Asset(AdminAbsoluteUrlMixin, PriceMixin, BaseObject): decimal_places=2, default=settings.DEFAULT_DEPRECIATION_RATE, help_text=_( - 'This value is in percentage.' + "This value is in percentage." ' For example value: "100" means it depreciates during a year.' ' Value: "25" means it depreciates during 4 years, and so on... .' ), max_digits=5, ) force_depreciation = models.BooleanField( - help_text=( - 'Check if you no longer want to bill for this asset' - ), + help_text=("Check if you no longer want to bill for this asset"), default=False, ) depreciation_end_date = models.DateField(blank=True, null=True) buyout_date = models.DateField(blank=True, null=True, db_index=True) task_url = models.URLField( blank=True, - help_text=('External workflow system URL'), + help_text=("External workflow system URL"), max_length=2048, null=True, ) @@ -471,13 +432,11 @@ class Asset(AdminAbsoluteUrlMixin, PriceMixin, BaseObject): start_usage = models.DateField( blank=True, null=True, - help_text=( - 'Fill it if date of first usage is different then date of creation' - ) + help_text=("Fill it if date of first usage is different then date of creation"), ) def __str__(self): - return self.hostname or '' + return self.hostname or "" def calculate_buyout_date(self): """ @@ -497,9 +456,7 @@ def calculate_buyout_date(self): return None category = self.model.category # type: Category - months = settings.ASSET_BUYOUT_CATEGORY_TO_MONTHS.get( - str(category.pk), None - ) + months = settings.ASSET_BUYOUT_CATEGORY_TO_MONTHS.get(str(category.pk), None) if self.invoice_date and months: return self.invoice_date + relativedelta(months=months) else: @@ -507,8 +464,7 @@ def calculate_buyout_date(self): def get_depreciation_months(self): return int( - (1 / (self.depreciation_rate / 100) * 12) - if self.depreciation_rate else 0 + (1 / (self.depreciation_rate / 100) * 12) if self.depreciation_rate else 0 ) def is_depreciated(self, date=None): @@ -534,27 +490,26 @@ def is_deprecated(self, date=None): return self.is_depreciated() def _liquidated_at(self, date): - liquidated_history = self.get_history().filter( - new_value='liquidated', - field_name='status', - ).order_by('-date')[:1] + liquidated_history = ( + self.get_history() + .filter( + new_value="liquidated", + field_name="status", + ) + .order_by("-date")[:1] + ) return liquidated_history and liquidated_history[0].date.date() <= date def clean(self): errors = {} if not self.sn and not self.barcode: - error_message = [_('SN or BARCODE field is required')] - errors.update( - { - 'sn': error_message, - 'barcode': error_message - } - ) + error_message = [_("SN or BARCODE field is required")] + errors.update({"sn": error_message, "barcode": error_message}) if not self.property_of: - error_message = [_('Property of field is required')] + error_message = [_("Property of field is required")] errors.update( { - '__all__': error_message, + "__all__": error_message, } ) if errors: @@ -565,9 +520,9 @@ def save(self, *args, **kwargs): # only one asset with empty barcode (because of `unique` constraint) # if you save barcode as None you could have many assets with empty # barcode (becasue `unique` constrainst is skipped) - for unique_field in ['barcode', 'sn']: + for unique_field in ["barcode", "sn"]: value = getattr(self, unique_field, None) - if value == '': + if value == "": value = None setattr(self, unique_field, value) diff --git a/src/ralph/assets/models/base.py b/src/ralph/assets/models/base.py index f41bea015d..e5e455cda8 100644 --- a/src/ralph/assets/models/base.py +++ b/src/ralph/assets/models/base.py @@ -6,26 +6,20 @@ from django.utils.translation import ugettext_lazy as _ from ralph.attachments.models import AttachmentItem -from ralph.lib.custom_fields.models import ( - CustomFieldMeta, - WithCustomFieldsMixin -) +from ralph.lib.custom_fields.models import CustomFieldMeta, WithCustomFieldsMixin from ralph.lib.mixins.models import TaggableMixin, TimeStampMixin from ralph.lib.permissions.models import PermByFieldMixin, PermissionsBase from ralph.lib.polymorphic.models import ( Polymorphic, PolymorphicBase, - PolymorphicQuerySet + PolymorphicQuerySet, ) from ralph.lib.transitions.models import TransitionWorkflowBase BaseObjectMeta = type( - 'BaseObjectMeta', ( - PolymorphicBase, - PermissionsBase, - CustomFieldMeta, - TransitionWorkflowBase - ), {} + "BaseObjectMeta", + (PolymorphicBase, PermissionsBase, CustomFieldMeta, TransitionWorkflowBase), + {}, ) @@ -41,9 +35,8 @@ def dc_hosts(self): * CloudHost """ from ralph.assets.utils import get_host_content_types - return self.filter( - content_type__in=get_host_content_types() - ) + + return self.filter(content_type__in=get_host_content_types()) class BaseObjectPolymorphicQuerySet(HostFilterMixin, PolymorphicQuerySet): @@ -57,7 +50,7 @@ class BaseObject( TimeStampMixin, WithCustomFieldsMixin, models.Model, - metaclass=BaseObjectMeta + metaclass=BaseObjectMeta, ): polymorphic_objects = BaseObjectPolymorphicQuerySet.as_manager() attachments = GenericRelation(AttachmentItem) @@ -65,31 +58,32 @@ class BaseObject( """Base object mixin.""" # TODO: dynamically limit parent basing on model parent = models.ForeignKey( - 'self', null=True, blank=True, related_name='children', - on_delete=models.SET_NULL + "self", + null=True, + blank=True, + related_name="children", + on_delete=models.SET_NULL, ) remarks = models.TextField(blank=True) service_env = models.ForeignKey( - 'ServiceEnvironment', null=True, blank=True, on_delete=models.PROTECT + "ServiceEnvironment", null=True, blank=True, on_delete=models.PROTECT ) @property def _str_with_type(self): - return '{}: {}'.format( - ContentType.objects.get_for_id(self.content_type_id), - str(self) + return "{}: {}".format( + ContentType.objects.get_for_id(self.content_type_id), str(self) ) configuration_path = models.ForeignKey( - 'ConfigurationClass', + "ConfigurationClass", null=True, blank=True, - verbose_name=_('configuration path'), + verbose_name=_("configuration path"), help_text=_( - 'path to configuration for this object, for example path to puppet ' - 'class' + "path to configuration for this object, for example path to puppet " "class" ), - on_delete=models.PROTECT + on_delete=models.PROTECT, ) @property @@ -97,7 +91,4 @@ def service(self): return self.service_env.service if self.service_env else None def get_absolute_url(self): - return reverse('admin:view_on_site', args=( - self.content_type_id, - self.pk - )) + return reverse("admin:view_on_site", args=(self.content_type_id, self.pk)) diff --git a/src/ralph/assets/models/choices.py b/src/ralph/assets/models/choices.py index dc52337b6f..cfa8ae40a8 100644 --- a/src/ralph/assets/models/choices.py +++ b/src/ralph/assets/models/choices.py @@ -6,91 +6,91 @@ class AssetPurpose(Choices): _ = Choices.Choice - for_contractor = _('for contractor') - sectional = _('sectional') - for_dashboards = _('for dashboards') - for_events = _('for events') - for_tests = _('for tests') - others = _('others') + for_contractor = _("for contractor") + sectional = _("sectional") + for_dashboards = _("for dashboards") + for_events = _("for events") + for_tests = _("for tests") + others = _("others") class AssetSource(Choices): _ = Choices.Choice - shipment = _('shipment') - salvaged = _('salvaged') + shipment = _("shipment") + salvaged = _("salvaged") class ObjectModelType(Choices): _ = Choices.Choice - back_office = _('back office') - data_center = _('data center') - part = _('part') - all = _('all') + back_office = _("back office") + data_center = _("data center") + part = _("part") + all = _("all") class ModelVisualizationLayout(Choices): # NOTE: append new layout _ = Choices.Choice - na = _('N/A') - layout_1x2 = _('1 row x 2 columns').extra(css_class='rows-1 cols-2') - layout_2x8 = _('2 rows x 8 columns').extra(css_class='rows-2 cols-8') - layout_2x8AB = _('2 rows x 16 columns (A/B)').extra( - css_class='rows-2 cols-8 half-slots' + na = _("N/A") + layout_1x2 = _("1 row x 2 columns").extra(css_class="rows-1 cols-2") + layout_2x8 = _("2 rows x 8 columns").extra(css_class="rows-2 cols-8") + layout_2x8AB = _("2 rows x 16 columns (A/B)").extra( + css_class="rows-2 cols-8 half-slots" ) - layout_4x2 = _('4 rows x 2 columns').extra(css_class='rows-4 cols-2') - layout_2x4 = _('2 rows x 4 columns').extra(css_class='rows-2 cols-4') - layout_2x2 = _('2 rows x 2 columns').extra(css_class='rows-2 cols-2') - layout_1x14 = _('1 rows x 14 columns').extra(css_class='rows-1 cols-14') - layout_2x1 = _('2 rows x 1 columns').extra(css_class='rows-2 cols-1') + layout_4x2 = _("4 rows x 2 columns").extra(css_class="rows-4 cols-2") + layout_2x4 = _("2 rows x 4 columns").extra(css_class="rows-2 cols-4") + layout_2x2 = _("2 rows x 2 columns").extra(css_class="rows-2 cols-2") + layout_1x14 = _("1 rows x 14 columns").extra(css_class="rows-1 cols-14") + layout_2x1 = _("2 rows x 1 columns").extra(css_class="rows-2 cols-1") class ComponentType(Choices): _ = Choices.Choice - processor = _('processor') - memory = _('memory') - disk = _('disk drive') - ethernet = _('ethernet card') - expansion = _('expansion card') - fibre = _('fibre channel card') - share = _('disk share') - unknown = _('unknown') - management = _('management') - power = _('power module') - cooling = _('cooling device') - media = _('media tray') - chassis = _('chassis') - backup = _('backup') - software = _('software') - os = _('operating system') + processor = _("processor") + memory = _("memory") + disk = _("disk drive") + ethernet = _("ethernet card") + expansion = _("expansion card") + fibre = _("fibre channel card") + share = _("disk share") + unknown = _("unknown") + management = _("management") + power = _("power module") + cooling = _("cooling device") + media = _("media tray") + chassis = _("chassis") + backup = _("backup") + software = _("software") + os = _("operating system") class EthernetSpeed(Choices): _ = Choices.Choice - s10mbit = _('10 Mbps') - s100mbit = _('100 Mbps') - s1gbit = _('1 Gbps') - s10gbit = _('10 Gbps') - s40gbit = _('40 Gbps') - s100gbit = _('100 Gbps') - s25gbit = _('25 Gbps') + s10mbit = _("10 Mbps") + s100mbit = _("100 Mbps") + s1gbit = _("1 Gbps") + s10gbit = _("10 Gbps") + s40gbit = _("40 Gbps") + s100gbit = _("100 Gbps") + s25gbit = _("25 Gbps") UNKNOWN_GROUP = Choices.Group(10) - unknown = _('unknown speed') + unknown = _("unknown speed") class FibreChannelCardSpeed(Choices): _ = Choices.Choice - s1gbit = _('1 Gbit') - s2gbit = _('2 Gbit') - s4gbit = _('4 Gbit') - s8gbit = _('8 Gbit') - s16gbit = _('16 Gbit') - s32gbit = _('32 Gbit') + s1gbit = _("1 Gbit") + s2gbit = _("2 Gbit") + s4gbit = _("4 Gbit") + s8gbit = _("8 Gbit") + s16gbit = _("16 Gbit") + s32gbit = _("32 Gbit") UNKNOWN_GROUP = Choices.Group(10) - unknown = _('unknown speed') + unknown = _("unknown speed") diff --git a/src/ralph/assets/models/components.py b/src/ralph/assets/models/components.py index 4e18fd8a3b..196efc76c6 100644 --- a/src/ralph/assets/models/components.py +++ b/src/ralph/assets/models/components.py @@ -12,16 +12,12 @@ from ralph.assets.models.choices import ( ComponentType, EthernetSpeed, - FibreChannelCardSpeed + FibreChannelCardSpeed, ) from ralph.lib.mixins.fields import MACAddressField, NullableCharField -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin -MAC_RE = re.compile(r'^\s*([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\s*$') +MAC_RE = re.compile(r"^\s*([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\s*$") MAC_ERROR_MSG = "'%(value)s' is not a valid MAC address." mac_validator = RegexValidator(regex=MAC_RE, message=MAC_ERROR_MSG) @@ -30,45 +26,42 @@ # but since it is used in some cloud-related functionality, it will be # removed later. class ComponentModel( - AdminAbsoluteUrlMixin, - AutocompleteTooltipMixin, - NamedMixin, - models.Model + AdminAbsoluteUrlMixin, AutocompleteTooltipMixin, NamedMixin, models.Model ): speed = models.PositiveIntegerField( - verbose_name=_('speed (MHz)'), + verbose_name=_("speed (MHz)"), default=0, blank=True, ) cores = models.PositiveIntegerField( - verbose_name=_('number of cores'), + verbose_name=_("number of cores"), default=0, blank=True, ) size = models.PositiveIntegerField( - verbose_name=_('size (MiB)'), + verbose_name=_("size (MiB)"), default=0, blank=True, ) type = models.PositiveIntegerField( - verbose_name=_('component type'), + verbose_name=_("component type"), choices=ComponentType(), default=ComponentType.unknown.id, ) - family = models.CharField(blank=True, default='', max_length=128) + family = models.CharField(blank=True, default="", max_length=128) autocomplete_tooltip_fields = [ - 'speed', - 'cores', - 'size', - 'type', - 'family', + "speed", + "cores", + "size", + "type", + "family", ] class Meta: - unique_together = ('speed', 'cores', 'size', 'type', 'family') - verbose_name = _('component model') - verbose_name_plural = _('component models') + unique_together = ("speed", "cores", "size", "type", "family") + verbose_name = _("component model") + verbose_name_plural = _("component models") def __str__(self): return self.name @@ -76,22 +69,23 @@ def __str__(self): class Component(AdminAbsoluteUrlMixin, TimeStampMixin, models.Model): base_object = models.ForeignKey( - BaseObject, - related_name='%(class)s_set', - on_delete=models.CASCADE + BaseObject, related_name="%(class)s_set", on_delete=models.CASCADE ) # TODO(xor-xor): This field should be removed along with ComponentModel # class. model = models.ForeignKey( ComponentModel, - verbose_name=_('model'), + verbose_name=_("model"), null=True, blank=True, default=None, on_delete=models.SET_NULL, ) model_name = models.CharField( - verbose_name=_('model name'), max_length=255, blank=True, null=True, + verbose_name=_("model name"), + max_length=255, + blank=True, + null=True, ) class Meta: @@ -100,53 +94,68 @@ class Meta: class GenericComponent(Component): label = models.CharField( - verbose_name=_('label'), max_length=255, blank=True, - null=True, default=None, + verbose_name=_("label"), + max_length=255, + blank=True, + null=True, + default=None, ) sn = NullableCharField( - verbose_name=_('vendor SN'), max_length=255, unique=True, null=True, - blank=True, default=None, + verbose_name=_("vendor SN"), + max_length=255, + unique=True, + null=True, + blank=True, + default=None, ) class Meta: - verbose_name = _('generic component') - verbose_name_plural = _('generic components') + verbose_name = _("generic component") + verbose_name_plural = _("generic components") class Ethernet(Component): label = NullableCharField( - verbose_name=_('label'), max_length=255, blank=True, null=True + verbose_name=_("label"), max_length=255, blank=True, null=True ) mac = MACAddressField( - verbose_name=_('MAC address'), unique=True, - validators=[mac_validator], max_length=24, null=True, blank=True + verbose_name=_("MAC address"), + unique=True, + validators=[mac_validator], + max_length=24, + null=True, + blank=True, ) speed = models.PositiveIntegerField( - verbose_name=_('speed'), choices=EthernetSpeed(), + verbose_name=_("speed"), + choices=EthernetSpeed(), default=EthernetSpeed.unknown.id, ) firmware_version = models.CharField( - verbose_name=_('firmware version'), max_length=255, blank=True, + verbose_name=_("firmware version"), + max_length=255, + blank=True, null=True, ) class Meta: - verbose_name = _('ethernet') - verbose_name_plural = _('ethernets') - ordering = ('base_object', 'mac') + verbose_name = _("ethernet") + verbose_name_plural = _("ethernets") + ordering = ("base_object", "mac") def __str__(self): - return '{} ({})'.format(self.label, self.mac) + return "{} ({})".format(self.label, self.mac) def _validate_expose_in_dhcp_and_mac(self): """ Check if mac is not empty when exposing in DHCP. """ from ralph.networks.models import IPAddress + try: if not self.mac and self.ipaddress.dhcp_expose: raise ValidationError( - _('MAC cannot be empty if record is exposed in DHCP') + _("MAC cannot be empty if record is exposed in DHCP") ) except IPAddress.DoesNotExist: pass @@ -157,13 +166,12 @@ def _validate_change_when_exposing_in_dhcp(self): """ if self.pk and settings.DHCP_ENTRY_FORBID_CHANGE: from ralph.networks.models import IPAddress + old_obj = self.__class__._default_manager.get(pk=self.pk) try: if old_obj.ipaddress.dhcp_expose: if old_obj.mac != self.mac: - raise ValidationError( - 'Cannot change MAC when exposing in DHCP' - ) + raise ValidationError("Cannot change MAC when exposing in DHCP") except IPAddress.DoesNotExist: pass @@ -172,7 +180,7 @@ def clean(self): for validator in [ super().clean, self._validate_expose_in_dhcp_and_mac, - self._validate_change_when_exposing_in_dhcp + self._validate_change_when_exposing_in_dhcp, ]: try: validator() @@ -185,37 +193,46 @@ def clean(self): class Memory(Component): size = models.PositiveIntegerField(verbose_name=_("size (MiB)")) speed = models.PositiveIntegerField( - verbose_name=_("speed (MHz)"), null=True, blank=True, + verbose_name=_("speed (MHz)"), + null=True, + blank=True, ) class Meta: - verbose_name = _('memory') - verbose_name_plural = _('memory') + verbose_name = _("memory") + verbose_name_plural = _("memory") def __str__(self): - return '{} MiB ({} MHz)'.format(self.size, self.speed) + return "{} MiB ({} MHz)".format(self.size, self.speed) class FibreChannelCard(Component): firmware_version = models.CharField( - verbose_name=_('firmware version'), max_length=255, blank=True, + verbose_name=_("firmware version"), + max_length=255, + blank=True, null=True, ) speed = models.PositiveIntegerField( - verbose_name=_('speed'), choices=FibreChannelCardSpeed(), + verbose_name=_("speed"), + choices=FibreChannelCardSpeed(), default=FibreChannelCardSpeed.unknown.id, ) # If you need PWWN (or any other *WWN), add a separate field for # it instead of using/re-using this one. wwn = NullableCharField( - verbose_name=_('WWN'), max_length=255, unique=True, null=True, - blank=True, default=None, + verbose_name=_("WWN"), + max_length=255, + unique=True, + null=True, + blank=True, + default=None, ) class Meta: - verbose_name = _('fibre channel card') - verbose_name_plural = _('fibre channel cards') + verbose_name = _("fibre channel card") + verbose_name_plural = _("fibre channel cards") def __str__(self): return 'model: "{}", WWN: "{}"'.format(self.model_name, self.wwn) @@ -223,7 +240,9 @@ def __str__(self): class Processor(Component): speed = models.PositiveIntegerField( - verbose_name=_("speed (MHz)"), null=True, blank=True, + verbose_name=_("speed (MHz)"), + null=True, + blank=True, ) cores = models.PositiveIntegerField( verbose_name="physical cores", null=True, blank=True @@ -231,32 +250,36 @@ class Processor(Component): logical_cores = models.PositiveIntegerField(null=True, blank=True) class Meta: - verbose_name = _('processor') - verbose_name_plural = _('processors') + verbose_name = _("processor") + verbose_name_plural = _("processors") def __str__(self): - return '{}: {} cores ({} MHz)'.format( - self.model_name, self.cores, self.speed - ) + return "{}: {} cores ({} MHz)".format(self.model_name, self.cores, self.speed) class Disk(Component): size = models.PositiveIntegerField(verbose_name=_("size (GiB)")) serial_number = models.CharField( - verbose_name=_('serial number'), max_length=255, blank=True, + verbose_name=_("serial number"), + max_length=255, + blank=True, null=True, ) slot = models.PositiveIntegerField( - verbose_name=_("slot number"), null=True, blank=True, + verbose_name=_("slot number"), + null=True, + blank=True, ) firmware_version = models.CharField( - verbose_name=_('firmware version'), max_length=255, blank=True, + verbose_name=_("firmware version"), + max_length=255, + blank=True, null=True, ) class Meta: - verbose_name = _('disk') - verbose_name_plural = _('disks') + verbose_name = _("disk") + verbose_name_plural = _("disks") def __str__(self): return 'model: "{}", size: "{}"'.format(self.model_name, self.size) diff --git a/src/ralph/assets/models/configuration.py b/src/ralph/assets/models/configuration.py index be501f3467..dd40299789 100644 --- a/src/ralph/assets/models/configuration.py +++ b/src/ralph/assets/models/configuration.py @@ -6,16 +6,13 @@ from mptt.models import MPTTModel, MPTTModelBase, TreeForeignKey from ralph.assets.models.base import BaseObject -from ralph.lib.custom_fields.models import ( - CustomFieldMeta, - WithCustomFieldsMixin -) +from ralph.lib.custom_fields.models import CustomFieldMeta, WithCustomFieldsMixin from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin -dir_file_name_validator = RegexValidator(regex=r'\w+') +dir_file_name_validator = RegexValidator(regex=r"\w+") ConfigurationModuleBase = type( - 'ConfigurationModuleBase', (MPTTModelBase, CustomFieldMeta), {} + "ConfigurationModuleBase", (MPTTModelBase, CustomFieldMeta), {} ) @@ -25,40 +22,40 @@ class ConfigurationModule( MPTTModel, TimeStampMixin, models.Model, - metaclass=ConfigurationModuleBase + metaclass=ConfigurationModuleBase, ): name = models.CharField( - verbose_name=_('name'), + verbose_name=_("name"), max_length=255, - help_text=_('module name (ex. directory name in puppet)'), + help_text=_("module name (ex. directory name in puppet)"), validators=[dir_file_name_validator], ) parent = TreeForeignKey( - 'self', - verbose_name=_('parent module'), + "self", + verbose_name=_("parent module"), null=True, blank=True, default=None, - related_name='children_modules', - on_delete=models.CASCADE + related_name="children_modules", + on_delete=models.CASCADE, ) # TODO: is this necessary? support_team = models.ForeignKey( - 'accounts.Team', - verbose_name=_('team'), + "accounts.Team", + verbose_name=_("team"), null=True, blank=True, default=None, - on_delete=models.SET_NULL + on_delete=models.SET_NULL, ) class Meta: - verbose_name = _('configuration module') - unique_together = ('parent', 'name') - ordering = ('parent__name', 'name') + verbose_name = _("configuration module") + unique_together = ("parent", "name") + ordering = ("parent__name", "name") class MPTTMeta: - order_insertion_by = ['name'] + order_insertion_by = ["name"] def __str__(self): return self.name @@ -72,35 +69,35 @@ def save(self, *args, **kwargs): class ConfigurationClass(AdminAbsoluteUrlMixin, BaseObject): class_name = models.CharField( - verbose_name=_('class name'), + verbose_name=_("class name"), max_length=255, - help_text=_('ex. puppet class'), + help_text=_("ex. puppet class"), validators=[dir_file_name_validator], ) path = models.CharField( - verbose_name=_('path'), + verbose_name=_("path"), blank=True, - default='', + default="", editable=False, max_length=511, # 255 form module name, '/' and 255 from class name - help_text=_('path is constructed from name of module and name of class') + help_text=_("path is constructed from name of module and name of class"), ) module = models.ForeignKey( ConfigurationModule, - related_name='configuration_classes', - on_delete=models.CASCADE + related_name="configuration_classes", + on_delete=models.CASCADE, ) autocomplete_words_split = True class Meta: - verbose_name = _('configuration class') - unique_together = ('module', 'class_name') - ordering = ('path',) + verbose_name = _("configuration class") + unique_together = ("module", "class_name") + ordering = ("path",) def __str__(self): return self.path def save(self, *args, **kwargs): - self.path = self.module.name + '/' + self.class_name + self.path = self.module.name + "/" + self.class_name super().save(*args, **kwargs) diff --git a/src/ralph/assets/signals.py b/src/ralph/assets/signals.py index 254b7587b5..53ec262640 100644 --- a/src/ralph/assets/signals.py +++ b/src/ralph/assets/signals.py @@ -1,4 +1,3 @@ - import logging from functools import partial, wraps @@ -8,7 +7,7 @@ from ralph.assets.models import BaseObject from ralph.data_center.publishers import ( publish_host_update, - publish_host_update_from_related_model + publish_host_update_from_related_model, ) from ralph.lib.custom_fields.signals import api_post_create, api_post_update from ralph.signals import post_commit @@ -18,7 +17,8 @@ def custom_field_change(sender, instance, **kwargs): from ralph.assets.utils import get_host_content_types - content_type = getattr(instance.object, 'content_type', None) + + content_type = getattr(instance.object, "content_type", None) if not content_type or content_type not in get_host_content_types(): return publish_host_update(instance.object) @@ -29,23 +29,22 @@ def custom_field_change(sender, instance, **kwargs): # trigger publish_host_update when related model change for model_path in [ - 'configuration_path', - 'configuration_path__module', - 'ethernet_set', - 'ethernet_set__ipaddress', + "configuration_path", + "configuration_path__module", + "ethernet_set", + "ethernet_set__ipaddress", ]: field = get_field_by_relation_path(BaseObject, model_path) model = get_model_from_relation(field) - logger.debug('Setting up handler for {} change of BaseObject'.format( - model.__name__, - )) + logger.debug( + "Setting up handler for {} change of BaseObject".format( + model.__name__, + ) + ) post_commit( # use wraps for keep magic attributes of func like __name__ wraps(publish_host_update_from_related_model)( - partial( - publish_host_update_from_related_model, - field_path=model_path - ) + partial(publish_host_update_from_related_model, field_path=model_path) ), - model + model, ) diff --git a/src/ralph/assets/subscribers.py b/src/ralph/assets/subscribers.py index 73b0b4c99b..ea49e62ba8 100644 --- a/src/ralph/assets/subscribers.py +++ b/src/ralph/assets/subscribers.py @@ -11,13 +11,13 @@ Environment, ProfitCenter, Service, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.models.base import BaseObject logger = logging.getLogger(__name__) -ACTION_TYPE = 'PROCESS_HERMES_UPDATE_SERVICE_EVENT' +ACTION_TYPE = "PROCESS_HERMES_UPDATE_SERVICE_EVENT" def _update_service_owners(service, business_owners, technical_owners): @@ -30,10 +30,10 @@ def _update_service_owners(service, business_owners, technical_owners): technical_owners: dict of owners """ business_owners = get_user_model().objects.filter( - username__in=[i['username'] for i in business_owners] + username__in=[i["username"] for i in business_owners] ) technical_owners = get_user_model().objects.filter( - username__in=[i['username'] for i in technical_owners] + username__in=[i["username"] for i in technical_owners] ) service.business_owners.set(business_owners) service.technical_owners.set(technical_owners) @@ -60,22 +60,19 @@ def _update_service_environments(service, environments): to_delete = current - new to_add = new - current for env_id in to_add: - ServiceEnvironment.objects.create( - service=service, - environment_id=env_id - ) + ServiceEnvironment.objects.create(service=service, environment_id=env_id) for env_id in to_delete: service_env = ServiceEnvironment.objects.get( service=service, environment_id=env_id ) if BaseObject.objects.filter(service_env=service_env).exists(): logger.error( - 'Can not delete service environment - it has assigned some base objects', # noqa: E501 + "Can not delete service environment - it has assigned some base objects", # noqa: E501 extra={ - 'action_type': ACTION_TYPE, - 'service_uid': service.uid, - 'service_name': service.name - } + "action_type": ACTION_TYPE, + "service_uid": service.uid, + "service_name": service.name, + }, ) return False service_env.delete() @@ -84,28 +81,22 @@ def _update_service_environments(service, environments): def _update_area(service, area_name): - if ( - not service.business_segment or - service.business_segment.name != area_name - ): + if not service.business_segment or service.business_segment.name != area_name: service.business_segment = BusinessSegment.objects.get_or_create( name=area_name )[0] def _update_profit_center(service, profit_center_name): - if ( - not service.profit_center or - service.profit_center.name != profit_center_name - ): + if not service.profit_center or service.profit_center.name != profit_center_name: service.profit_center = ProfitCenter.objects.get_or_create( name=profit_center_name )[0] -@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS['CREATE']) -@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS['UPDATE']) -@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS['REFRESH']) +@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS["CREATE"]) +@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS["UPDATE"]) +@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS["REFRESH"]) def update_service_handler(service_data): """ Update information about Service from Hermes event. @@ -133,90 +124,87 @@ def update_service_handler(service_data): """ try: service, _ = Service.objects.update_or_create( - uid=service_data['uid'], + uid=service_data["uid"], defaults={ - 'name': service_data['name'], - } + "name": service_data["name"], + }, ) except Exception as e: logger.exception( e, extra={ - 'action_type': ACTION_TYPE, - 'service_uid': service_data['uid'], - 'service_name': service_data['name'] - } + "action_type": ACTION_TYPE, + "service_uid": service_data["uid"], + "service_name": service_data["name"], + }, ) else: _update_service_owners( service=service, - business_owners=service_data['businessOwners'], - technical_owners=service_data['technicalOwners'] + business_owners=service_data["businessOwners"], + technical_owners=service_data["technicalOwners"], ) - if service_data.get('area'): - _update_area(service, service_data['area']['name']) - if service_data['area'].get('profitCenter'): - _update_profit_center( - service, service_data['area']['profitCenter'] - ) + if service_data.get("area"): + _update_area(service, service_data["area"]["name"]) + if service_data["area"].get("profitCenter"): + _update_profit_center(service, service_data["area"]["profitCenter"]) update_envs = _update_service_environments( - service=service, - environments=service_data['environments'] + service=service, environments=service_data["environments"] ) if update_envs: - service.active = service_data['isActive'] + service.active = service_data["isActive"] service.save() logger.info( - 'Synced service `{}` with UID `{}`.'.format( - service_data['name'], service_data['uid'] + "Synced service `{}` with UID `{}`.".format( + service_data["name"], service_data["uid"] ), extra={ - 'action_type': ACTION_TYPE, - 'service_uid': service_data['uid'], - 'service_name': service_data['name'] - } + "action_type": ACTION_TYPE, + "service_uid": service_data["uid"], + "service_name": service_data["name"], + }, ) -@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS['DELETE']) +@pyhermes.subscriber(topic=settings.HERMES_SERVICE_TOPICS["DELETE"]) def delete_service_handler(service_data): """ Set service active to False if service deleted. """ try: service_envs = ServiceEnvironment.objects.filter( - service__uid=service_data['uid'] + service__uid=service_data["uid"] ) if BaseObject.objects.filter(service_env__in=service_envs).exists(): logger.error( - 'Can not delete service - it has assigned some base objects', + "Can not delete service - it has assigned some base objects", extra={ - 'action_type': ACTION_TYPE, - 'service_uid': service_data['uid'], - 'service_name': service_data['name'] - } + "action_type": ACTION_TYPE, + "service_uid": service_data["uid"], + "service_name": service_data["name"], + }, ) return - Service.objects.filter(uid=service_data['uid']).update(active=False) + Service.objects.filter(uid=service_data["uid"]).update(active=False) except Exception as e: logger.exception( e, extra={ - 'action_type': ACTION_TYPE, - 'service_uid': service_data['uid'], - 'service_name': service_data['name'] - } + "action_type": ACTION_TYPE, + "service_uid": service_data["uid"], + "service_name": service_data["name"], + }, ) else: logger.info( - 'Service `{}` with UID `{}` deleted.'.format( - service_data['name'], service_data['uid'] + "Service `{}` with UID `{}` deleted.".format( + service_data["name"], service_data["uid"] ), extra={ - 'action_type': ACTION_TYPE, - 'service_uid': service_data['uid'], - 'service_name': service_data['name'] - } + "action_type": ACTION_TYPE, + "service_uid": service_data["uid"], + "service_name": service_data["name"], + }, ) diff --git a/src/ralph/assets/tests/factories.py b/src/ralph/assets/tests/factories.py index 90726f6a8e..4aea1dbe8c 100644 --- a/src/ralph/assets/tests/factories.py +++ b/src/ralph/assets/tests/factories.py @@ -14,7 +14,7 @@ ManufacturerKind, ProfitCenter, Service, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.models.base import BaseObject from ralph.assets.models.choices import ComponentType, ObjectModelType @@ -24,24 +24,14 @@ Ethernet, FibreChannelCard, Memory, - Processor -) -from ralph.assets.models.configuration import ( - ConfigurationClass, - ConfigurationModule + Processor, ) +from ralph.assets.models.configuration import ConfigurationClass, ConfigurationModule def next_mac(n): - mac = [ - 0x00, - 0x16, - 0x3e, - n >> 16 & 0xff, - n >> 8 & 0xff, - n & 0xff - ] - return ':'.join(map(lambda x: '%02x' % x, mac)) + mac = [0x00, 0x16, 0x3E, n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF] + return ":".join(map(lambda x: "%02x" % x, mac)) def next_wwn(n): @@ -54,133 +44,151 @@ def next_wwn(n): # ... # n = 32 gives 'aabbccddee000020', # ...and so on. - wwn = [ - 0xaa, - 0xbb, - 0xcc, - 0xdd, - 0xee, - n >> 16 & 0xff, - n >> 8 & 0xff, - n & 0xff - ] - return ''.join(map(lambda x: '%02x' % x, wwn)) + wwn = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF] + return "".join(map(lambda x: "%02x" % x, wwn)) class ComponentModelFactory(DjangoModelFactory): - - speed = factory.Iterator(['2700', '2500', '2100']) - cores = factory.Iterator(['2', '4', '8']) - size = factory.Iterator(['512', '1024', '2048']) - type = factory.Iterator([ - ComponentType.processor.id, ComponentType.memory.id, - ComponentType.disk.id, ComponentType.ethernet.id - ]) + speed = factory.Iterator(["2700", "2500", "2100"]) + cores = factory.Iterator(["2", "4", "8"]) + size = factory.Iterator(["512", "1024", "2048"]) + type = factory.Iterator( + [ + ComponentType.processor.id, + ComponentType.memory.id, + ComponentType.disk.id, + ComponentType.ethernet.id, + ] + ) name = FuzzyText() family = FuzzyText() class Meta: model = ComponentModel - django_get_or_create = [ - 'name', 'speed', 'cores', 'size', 'type', 'family' - ] + django_get_or_create = ["name", "speed", "cores", "size", "type", "family"] class BaseObjectFactory(DjangoModelFactory): - class Meta: model = BaseObject class CategoryFactory(DjangoModelFactory): - imei_required = True show_buyout_date = True - name = factory.Iterator([ - 'Dictaphone', 'Disk', 'External disk', 'External drive', 'Headphones', - 'Keyboard', 'Mouse', 'Pendrive', 'Notebook' - ]) + name = factory.Iterator( + [ + "Dictaphone", + "Disk", + "External disk", + "External drive", + "Headphones", + "Keyboard", + "Mouse", + "Pendrive", + "Notebook", + ] + ) class Meta: model = Category - django_get_or_create = ['name'] + django_get_or_create = ["name"] class DataCenterCategoryFactory(DjangoModelFactory): - imei_required = False - name = factory.Iterator([ - 'ATS', 'Database Machine', 'Blade System', 'Chassis blade' - ]) + name = factory.Iterator( + ["ATS", "Database Machine", "Blade System", "Chassis blade"] + ) class Meta: model = Category - django_get_or_create = ['name'] + django_get_or_create = ["name"] class AssetHolderFactory(DjangoModelFactory): - - name = factory.Iterator( - ['Grupa Allegro SP. z o.o.', 'Google Inc.', 'Dell Inc'] - ) + name = factory.Iterator(["Grupa Allegro SP. z o.o.", "Google Inc.", "Dell Inc"]) class Meta: model = AssetHolder - django_get_or_create = ['name'] + django_get_or_create = ["name"] class BudgetInfoFactory(DjangoModelFactory): - - name = factory.Iterator( - ['Python Team', 'Django team', 'Redis Team', 'PSQL Team'] - ) + name = factory.Iterator(["Python Team", "Django team", "Redis Team", "PSQL Team"]) class Meta: model = BudgetInfo - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ManufacturerKindFactory(DjangoModelFactory): - - name = factory.Iterator([ - 'kind-a', 'kind-b', 'kind-c', - ]) + name = factory.Iterator( + [ + "kind-a", + "kind-b", + "kind-c", + ] + ) class Meta: model = ManufacturerKind - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ManufacturerFactory(DjangoModelFactory): - - name = factory.Iterator([ - 'Dell', 'Apple', 'Samsung', 'Adobe', 'Asus', 'Atlassian', 'BenQ', - 'Belkin', 'Bosh', 'Brother', 'Foxconn', 'Fujitsu', 'HUAWEI', 'HTC' - ]) + name = factory.Iterator( + [ + "Dell", + "Apple", + "Samsung", + "Adobe", + "Asus", + "Atlassian", + "BenQ", + "Belkin", + "Bosh", + "Brother", + "Foxconn", + "Fujitsu", + "HUAWEI", + "HTC", + ] + ) class Meta: model = Manufacturer - django_get_or_create = ['name'] + django_get_or_create = ["name"] class BackOfficeAssetModelFactory(DjangoModelFactory): - - name = factory.Iterator([ - '3310', 'XD300S', 'Hero 3', 'Computer set', 'Advance', 'axs', 'compaq', - 'Dell XPS', 'Macbook', 'Iphone 6', 'Iphone 6S', 'Desire' - ]) + name = factory.Iterator( + [ + "3310", + "XD300S", + "Hero 3", + "Computer set", + "Advance", + "axs", + "compaq", + "Dell XPS", + "Macbook", + "Iphone 6", + "Iphone 6S", + "Desire", + ] + ) type = ObjectModelType.back_office category = factory.SubFactory(CategoryFactory) manufacturer = factory.SubFactory(ManufacturerFactory) class Meta: model = AssetModel - django_get_or_create = ['name'] + django_get_or_create = ["name"] class DataCenterAssetModelFactory(DjangoModelFactory): - - name = factory.Iterator(['DL360', 'DL380p', 'DL380', 'ML10', 'ML10 v21']) + name = factory.Iterator(["DL360", "DL380p", "DL380", "ML10", "ML10 v21"]) type = ObjectModelType.data_center manufacturer = factory.SubFactory(ManufacturerFactory) height_of_device = factory.Iterator([1, 2, 3, 4]) @@ -188,88 +196,84 @@ class DataCenterAssetModelFactory(DjangoModelFactory): class Meta: model = AssetModel - django_get_or_create = ['name'] + django_get_or_create = ["name"] class EnvironmentFactory(DjangoModelFactory): - - name = factory.Iterator(['prod', 'dev', 'test']) + name = factory.Iterator(["prod", "dev", "test"]) class Meta: model = Environment - django_get_or_create = ['name'] + django_get_or_create = ["name"] class BusinessSegmentFactory(DjangoModelFactory): - name = factory.Iterator(['IT', 'Ads', 'Research']) + name = factory.Iterator(["IT", "Ads", "Research"]) class Meta: model = BusinessSegment - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ProfitCenterFactory(DjangoModelFactory): - name = factory.Iterator(['PC1', 'PC2', 'PC3']) + name = factory.Iterator(["PC1", "PC2", "PC3"]) class Meta: model = ProfitCenter - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ServiceFactory(DjangoModelFactory): - - name = factory.Iterator(['Backup systems', 'load_balancing', 'databases']) - uid = factory.Sequence(lambda n: 'sc-{}'.format(n)) + name = factory.Iterator(["Backup systems", "load_balancing", "databases"]) + uid = factory.Sequence(lambda n: "sc-{}".format(n)) business_segment = factory.SubFactory(BusinessSegmentFactory) profit_center = factory.SubFactory(ProfitCenterFactory) class Meta: model = Service - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ServiceEnvironmentFactory(DjangoModelFactory): - service = factory.SubFactory(ServiceFactory) environment = factory.SubFactory(EnvironmentFactory) class Meta: model = ServiceEnvironment - django_get_or_create = ['service', 'environment'] + django_get_or_create = ["service", "environment"] class EthernetFactory(DjangoModelFactory): base_object = factory.SubFactory(BaseObjectFactory) - label = factory.Sequence(lambda n: 'ETH#{}'.format(n)) + label = factory.Sequence(lambda n: "ETH#{}".format(n)) mac = factory.Sequence(next_mac) class Meta: model = Ethernet - django_get_or_create = ['label'] + django_get_or_create = ["label"] class EthernetWithIPAddressFactory(EthernetFactory): ipaddress = factory.RelatedFactory( - 'ralph.networks.tests.factories.IPAddressWithNetworkFactory', - 'ethernet' + "ralph.networks.tests.factories.IPAddressWithNetworkFactory", "ethernet" ) class ConfigurationModuleFactory(DjangoModelFactory): - name = factory.Iterator(['ralph', 'allegro', 'auth', 'order']) + name = factory.Iterator(["ralph", "allegro", "auth", "order"]) class Meta: model = ConfigurationModule - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ConfigurationClassFactory(DjangoModelFactory): - class_name = factory.Iterator(['www', 'db', 'worker', 'cache']) + class_name = factory.Iterator(["www", "db", "worker", "cache"]) module = factory.SubFactory(ConfigurationModuleFactory) class Meta: model = ConfigurationClass - django_get_or_create = ['class_name'] + django_get_or_create = ["class_name"] class MemoryFactory(DjangoModelFactory): @@ -284,9 +288,7 @@ class Meta: class FibreChannelCardFactory(DjangoModelFactory): base_object = factory.SubFactory(BaseObjectFactory) - firmware_version = factory.Iterator( - ['1.1.1', '1.1.2', '1.1.3', '1.1.4', '1.1.5'] - ) + firmware_version = factory.Iterator(["1.1.1", "1.1.2", "1.1.3", "1.1.4", "1.1.5"]) model_name = "Saturn-X: LightPulse Fibre Channel Host Adapter" wwn = factory.Sequence(next_wwn) @@ -307,11 +309,9 @@ class Meta: class DiskFactory(DjangoModelFactory): base_object = factory.SubFactory(BaseObjectFactory) size = factory.Iterator([476, 256]) - serial_number = factory.Sequence(lambda n: 'S1234{}'.format(n)) + serial_number = factory.Sequence(lambda n: "S1234{}".format(n)) slot = factory.Iterator([0, 1, 2, 3, 4, 5, 6, 7]) - firmware_version = factory.Iterator( - ['1.1.1', '1.1.2', '1.1.3', '1.1.4', '1.1.5'] - ) + firmware_version = factory.Iterator(["1.1.1", "1.1.2", "1.1.3", "1.1.4", "1.1.5"]) model_name = factory.Iterator(["ATA Samsung SSD", "Toshiba SSD"]) class Meta: diff --git a/src/ralph/assets/tests/test_api.py b/src/ralph/assets/tests/test_api.py index a38c4dbd0c..b8a2bef720 100644 --- a/src/ralph/assets/tests/test_api.py +++ b/src/ralph/assets/tests/test_api.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from urllib.parse import urlencode -from ddt import data, ddt, unpack +from ddt import data, ddt from django.urls import reverse from rest_framework import status @@ -17,7 +17,7 @@ Manufacturer, ObjectModelType, Service, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.tests.factories import ( BusinessSegmentFactory, @@ -30,7 +30,7 @@ ManufacturerFactory, ProfitCenterFactory, ServiceEnvironmentFactory, - ServiceFactory + ServiceFactory, ) from ralph.back_office.models import BackOfficeAsset from ralph.back_office.tests.factories import BackOfficeAssetFactory @@ -42,7 +42,7 @@ DatabaseFactory, DataCenterAssetFactory, DataCenterAssetFullFactory, - VIPFactory + VIPFactory, ) from ralph.domains.models import Domain from ralph.domains.tests.factories import DomainFactory @@ -60,21 +60,16 @@ DesignFactory, PatentFactory, TradeMarkFactory, - UtilityModelFactory -) -from ralph.virtual.models import ( - CloudFlavor, - CloudHost, - CloudProject, - VirtualServer + UtilityModelFactory, ) +from ralph.virtual.models import CloudFlavor, CloudHost, CloudProject, VirtualServer from ralph.virtual.tests.factories import ( CloudFlavorFactory, CloudHostFactory, CloudHostFullFactory, CloudProjectFactory, VirtualServerFactory, - VirtualServerFullFactory + VirtualServerFullFactory, ) @@ -87,41 +82,35 @@ def setUp(self): @data( 1, - '1', - 'true', - 'True', - 'yes', + "1", + "true", + "True", + "yes", ) def test_filter_by_active(self, active): - url = '{}?{}'.format( - reverse('service-list'), urlencode({'active': active}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("service-list"), urlencode({"active": active})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 2) + self.assertEqual(response.data["count"], 2) @data( 0, - '0', - 'false', - 'False', - 'no', + "0", + "false", + "False", + "no", ) def test_filter_by_inactive(self, active): - url = '{}?{}'.format( - reverse('service-list'), urlencode({'active': active}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("service-list"), urlencode({"active": active})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_filter_by_active_invalid_value_should_return_all(self): - url = '{}?{}'.format( - reverse('service-list'), urlencode({'active': 'invalid'}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("service-list"), urlencode({"active": "invalid"})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 3) + self.assertEqual(response.data["count"], 3) class ServicesEnvironmentsAPITests(RalphAPITestCase): @@ -137,61 +126,55 @@ def setUp(self): def test_get_environment(self): env = self.envs[0] - url = reverse('environment-detail', args=(env.id,)) - response = self.client.get(url, format='json') + url = reverse("environment-detail", args=(env.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], env.name) - self.assertIn('url', response.data) + self.assertEqual(response.data["name"], env.name) + self.assertIn("url", response.data) def test_create_environment(self): - url = reverse('environment-list') - data = { - 'name': 'test-env' - } - response = self.client.post(url, data, format='json') + url = reverse("environment-list") + data = {"name": "test-env"} + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data['name'], 'test-env') + self.assertEqual(response.data["name"], "test-env") self.assertEqual(Environment.objects.count(), 3) def test_patch_environment(self): env = self.envs[0] - url = reverse('environment-detail', args=(env.id,)) - data = { - 'name': 'test-env-2' - } - response = self.client.patch(url, data, format='json') + url = reverse("environment-detail", args=(env.id,)) + data = {"name": "test-env-2"} + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], 'test-env-2') + self.assertEqual(response.data["name"], "test-env-2") def test_get_service(self): service = self.services[0] - url = reverse('service-detail', args=(service.id,)) - response = self.client.get(url, format='json') + url = reverse("service-detail", args=(service.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], service.name) + self.assertEqual(response.data["name"], service.name) self.assertEqual( - response.data['environments'][0]['id'], - service.environments.all()[0].id + response.data["environments"][0]["id"], service.environments.all()[0].id ) def test_create_service(self): - url = reverse('service-list') + url = reverse("service-list") data = { - 'name': 'test-service', - 'environments': [self.envs[0].id, self.envs[1].id], - 'business_owners': [self.user1.id], - 'technical_owners': [self.user2.id], - 'support_team': self.team.id, - 'profit_center': self.profit_center.id, + "name": "test-service", + "environments": [self.envs[0].id, self.envs[1].id], + "business_owners": [self.user1.id], + "technical_owners": [self.user2.id], + "support_team": self.team.id, + "profit_center": self.profit_center.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Service.objects.count(), 3) - service = Service.objects.get(pk=response.data['id']) - self.assertEqual(service.name, 'test-service') + service = Service.objects.get(pk=response.data["id"]) + self.assertEqual(service.name, "test-service") self.assertCountEqual( - service.environments.values_list('id', flat=True), - data['environments'] + service.environments.values_list("id", flat=True), data["environments"] ) self.assertIn(self.user1, service.business_owners.all()) self.assertIn(self.user2, service.technical_owners.all()) @@ -199,23 +182,22 @@ def test_create_service(self): self.assertEqual(service.support_team, self.team) def test_create_service_with_names_instead_of_ids(self): - url = reverse('service-list') + url = reverse("service-list") data = { - 'name': 'test-service', - 'environments': [self.envs[0].name, self.envs[1].name], - 'business_owners': [self.user1.username], - 'technical_owners': [self.user2.username], - 'support_team': self.team.name, - 'profit_center': self.profit_center.name, + "name": "test-service", + "environments": [self.envs[0].name, self.envs[1].name], + "business_owners": [self.user1.username], + "technical_owners": [self.user2.username], + "support_team": self.team.name, + "profit_center": self.profit_center.name, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Service.objects.count(), 3) - service = Service.objects.get(pk=response.data['id']) - self.assertEqual(service.name, 'test-service') + service = Service.objects.get(pk=response.data["id"]) + self.assertEqual(service.name, "test-service") self.assertCountEqual( - service.environments.values_list('name', flat=True), - data['environments'] + service.environments.values_list("name", flat=True), data["environments"] ) self.assertIn(self.user1, service.business_owners.all()) self.assertIn(self.user2, service.technical_owners.all()) @@ -223,23 +205,22 @@ def test_create_service_with_names_instead_of_ids(self): self.assertEqual(service.support_team, self.team) def test_create_service_with_nulls(self): - url = reverse('service-list') + url = reverse("service-list") data = { - 'name': 'test-service', - 'environments': [self.envs[0].name, self.envs[1].name], - 'business_owners': [self.user1.username], - 'technical_owners': [self.user2.username], - 'support_team': None, - 'profit_center': None, + "name": "test-service", + "environments": [self.envs[0].name, self.envs[1].name], + "business_owners": [self.user1.username], + "technical_owners": [self.user2.username], + "support_team": None, + "profit_center": None, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Service.objects.count(), 3) - service = Service.objects.get(pk=response.data['id']) - self.assertEqual(service.name, 'test-service') + service = Service.objects.get(pk=response.data["id"]) + self.assertEqual(service.name, "test-service") self.assertCountEqual( - service.environments.values_list('name', flat=True), - data['environments'] + service.environments.values_list("name", flat=True), data["environments"] ) self.assertIn(self.user1, service.business_owners.all()) self.assertIn(self.user2, service.technical_owners.all()) @@ -247,21 +228,20 @@ def test_create_service_with_nulls(self): self.assertIsNone(service.support_team, self.team) def test_create_service_with_without_profit_center_and_support_team(self): - url = reverse('service-list') + url = reverse("service-list") data = { - 'name': 'test-service', - 'environments': [self.envs[0].name, self.envs[1].name], - 'business_owners': [self.user1.username], - 'technical_owners': [self.user2.username], + "name": "test-service", + "environments": [self.envs[0].name, self.envs[1].name], + "business_owners": [self.user1.username], + "technical_owners": [self.user2.username], } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Service.objects.count(), 3) - service = Service.objects.get(pk=response.data['id']) - self.assertEqual(service.name, 'test-service') + service = Service.objects.get(pk=response.data["id"]) + self.assertEqual(service.name, "test-service") self.assertCountEqual( - service.environments.values_list('name', flat=True), - data['environments'] + service.environments.values_list("name", flat=True), data["environments"] ) self.assertIn(self.user1, service.business_owners.all()) self.assertIn(self.user2, service.technical_owners.all()) @@ -270,19 +250,18 @@ def test_create_service_with_without_profit_center_and_support_team(self): def test_patch_service(self): service = self.services[1] - url = reverse('service-detail', args=(service.id,)) + url = reverse("service-detail", args=(service.id,)) data = { - 'name': 'test-service-2', - 'environments': [self.envs[1].id], - 'technical_owners': [self.user2.id], + "name": "test-service-2", + "environments": [self.envs[1].id], + "technical_owners": [self.user2.id], } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) service.refresh_from_db() - self.assertEqual(service.name, 'test-service-2') + self.assertEqual(service.name, "test-service-2") self.assertCountEqual( - service.environments.values_list('id', flat=True), - data['environments'] + service.environments.values_list("id", flat=True), data["environments"] ) self.assertIn(self.user2, service.technical_owners.all()) @@ -293,21 +272,17 @@ def test_patch_service_keep_environments_when_not_in_request(self): """ service = self.services[0] environments_ids = [env.id for env in service.environments.all()] - service_env_ids = [ - se.id for se in service.serviceenvironment_set.all() - ] - url = reverse('service-detail', args=(service.id,)) + service_env_ids = [se.id for se in service.serviceenvironment_set.all()] + url = reverse("service-detail", args=(service.id,)) data = { - 'name': 'test-service-2', + "name": "test-service-2", } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) service.refresh_from_db() - self.assertEqual(service.name, 'test-service-2') + self.assertEqual(service.name, "test-service-2") new_environments_ids = [env.id for env in service.environments.all()] - new_service_env_ids = [ - se.id for se in service.serviceenvironment_set.all() - ] + new_service_env_ids = [se.id for se in service.serviceenvironment_set.all()] self.assertCountEqual(environments_ids, new_environments_ids) self.assertCountEqual(service_env_ids, new_service_env_ids) @@ -317,57 +292,47 @@ def test_patch_service_keep_environments_ids(self): """ service = self.services[0] environments_ids = [env.id for env in service.environments.all()] - service_env_ids = [ - se.id for se in service.serviceenvironment_set.all() - ] - url = reverse('service-detail', args=(service.id,)) + service_env_ids = [se.id for se in service.serviceenvironment_set.all()] + url = reverse("service-detail", args=(service.id,)) data = { - 'name': 'test-service-2', - 'environments': environments_ids, + "name": "test-service-2", + "environments": environments_ids, } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) service.refresh_from_db() - self.assertEqual(service.name, 'test-service-2') + self.assertEqual(service.name, "test-service-2") new_environments_ids = [env.id for env in service.environments.all()] - new_service_env_ids = [ - se.id for se in service.serviceenvironment_set.all() - ] + new_service_env_ids = [se.id for se in service.serviceenvironment_set.all()] self.assertCountEqual(environments_ids, new_environments_ids) self.assertCountEqual(service_env_ids, new_service_env_ids) def test_get_service_environment(self): service_env = ServiceEnvironment.objects.all()[0] - url = reverse('serviceenvironment-detail', args=(service_env.id,)) - response = self.client.get(url, format='json') + url = reverse("serviceenvironment-detail", args=(service_env.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['service']['id'], service_env.service.id) - self.assertEqual( - response.data['environment']['id'], service_env.environment.id - ) + self.assertEqual(response.data["service"]["id"], service_env.service.id) + self.assertEqual(response.data["environment"]["id"], service_env.environment.id) def test_create_service_should_return_method_not_allowed(self): - url = reverse('serviceenvironment-list') + url = reverse("serviceenvironment-list") data = { - 'service': self.services[0].id, - 'environment': self.envs[0].id, + "service": self.services[0].id, + "environment": self.envs[0].id, } - response = self.client.post(url, data, format='json') - self.assertEqual( - response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED - ) + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) def test_patch_service_should_return_method_not_allowed(self): service_env = ServiceEnvironment.objects.all()[0] - url = reverse('serviceenvironment-detail', args=(service_env.id,)) + url = reverse("serviceenvironment-detail", args=(service_env.id,)) data = { - 'service': self.services[0].id, - 'environment': self.envs[0].id, + "service": self.services[0].id, + "environment": self.envs[0].id, } - response = self.client.patch(url, data, format='json') - self.assertEqual( - response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED - ) + response = self.client.patch(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) class ProfitCenterAPITests(RalphAPITestCase): @@ -376,19 +341,17 @@ def setUp(self): self.profit_center = ProfitCenterFactory() def test_get_profit_center_list(self): - url = reverse('profitcenter-list') - response = self.client.get(url, format='json') + url = reverse("profitcenter-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - self.assertEqual( - response.data['results'][0]['name'], self.profit_center.name - ) + self.assertEqual(response.data["count"], 1) + self.assertEqual(response.data["results"][0]["name"], self.profit_center.name) def test_get_profit_center_details(self): - url = reverse('profitcenter-detail', args=(self.profit_center.id,)) - response = self.client.get(url, format='json') + url = reverse("profitcenter-detail", args=(self.profit_center.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.profit_center.name) + self.assertEqual(response.data["name"], self.profit_center.name) class BusinessSegmentAPITests(RalphAPITestCase): @@ -397,19 +360,19 @@ def setUp(self): self.business_segment = BusinessSegmentFactory() def test_get_business_segment_list(self): - url = reverse('businesssegment-list') - response = self.client.get(url, format='json') + url = reverse("businesssegment-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) self.assertEqual( - response.data['results'][0]['name'], self.business_segment.name + response.data["results"][0]["name"], self.business_segment.name ) def test_get_business_segment_details(self): - url = reverse('businesssegment-detail', args=(self.business_segment.id,)) - response = self.client.get(url, format='json') + url = reverse("businesssegment-detail", args=(self.business_segment.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.business_segment.name) + self.assertEqual(response.data["name"], self.business_segment.name) class ManufacturerAPITests(RalphAPITestCase): @@ -418,99 +381,86 @@ def setUp(self): self.manufacturer = ManufacturerFactory() def test_get_manufacturer_list(self): - url = reverse('manufacturer-list') - response = self.client.get(url, format='json') + url = reverse("manufacturer-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - self.assertEqual( - response.data['results'][0]['name'], self.manufacturer.name - ) + self.assertEqual(response.data["count"], 1) + self.assertEqual(response.data["results"][0]["name"], self.manufacturer.name) def test_get_manufacturer_details(self): - url = reverse('manufacturer-detail', args=(self.manufacturer.id,)) - response = self.client.get(url, format='json') + url = reverse("manufacturer-detail", args=(self.manufacturer.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.manufacturer.name) + self.assertEqual(response.data["name"], self.manufacturer.name) def test_create_manufacturer(self): - url = reverse('manufacturer-list') - data = { - 'name': 'Lenovo' - } - response = self.client.post(url, data, format='json') + url = reverse("manufacturer-list") + data = {"name": "Lenovo"} + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data['name'], 'Lenovo') + self.assertEqual(response.data["name"], "Lenovo") self.assertEqual(Manufacturer.objects.count(), 2) def test_patch_manufacturer(self): - url = reverse('manufacturer-detail', args=(self.manufacturer.id,)) - data = { - 'name': 'Lenovo' - } - response = self.client.patch(url, data, format='json') + url = reverse("manufacturer-detail", args=(self.manufacturer.id,)) + data = {"name": "Lenovo"} + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.manufacturer.refresh_from_db() - self.assertEqual(self.manufacturer.name, 'Lenovo') + self.assertEqual(self.manufacturer.name, "Lenovo") class CategoryAPITests(RalphAPITestCase): def setUp(self): super().setUp() - self.category = CategoryFactory(name='rack-servers') + self.category = CategoryFactory(name="rack-servers") def test_get_category_list(self): - url = reverse('category-list') - response = self.client.get(url, format='json') + url = reverse("category-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - self.assertEqual( - response.data['results'][0]['name'], self.category.name - ) + self.assertEqual(response.data["count"], 1) + self.assertEqual(response.data["results"][0]["name"], self.category.name) def test_get_category_details(self): - url = reverse('category-detail', args=(self.category.id,)) - response = self.client.get(url, format='json') + url = reverse("category-detail", args=(self.category.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.category.name) + self.assertEqual(response.data["name"], self.category.name) def test_create_category(self): - url = reverse('category-list') - data = { - 'name': 'cell-phones', - 'code': 'cp' - } - response = self.client.post(url, data, format='json') + url = reverse("category-list") + data = {"name": "cell-phones", "code": "cp"} + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data['name'], 'cell-phones') + self.assertEqual(response.data["name"], "cell-phones") self.assertEqual(Category.objects.count(), 2) - category = Category.objects.get(pk=response.data['id']) - self.assertEqual(category.name, 'cell-phones') - self.assertEqual(category.code, 'cp') + category = Category.objects.get(pk=response.data["id"]) + self.assertEqual(category.name, "cell-phones") + self.assertEqual(category.code, "cp") self.assertIsNone(category.parent) def test_create_category_with_parent(self): - url = reverse('category-list') + url = reverse("category-list") data = { - 'name': 'cell-phones', - 'parent': self.category.id, + "name": "cell-phones", + "parent": self.category.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data['name'], 'cell-phones') + self.assertEqual(response.data["name"], "cell-phones") self.assertEqual(Category.objects.count(), 2) - category = Category.objects.get(pk=response.data['id']) - self.assertEqual(category.name, 'cell-phones') + category = Category.objects.get(pk=response.data["id"]) + self.assertEqual(category.name, "cell-phones") self.assertEqual(category.parent, self.category) def test_patch_category(self): - url = reverse('category-detail', args=(self.category.id,)) - data = { - 'name': 'cell-phones' - } - response = self.client.patch(url, data, format='json') + url = reverse("category-detail", args=(self.category.id,)) + data = {"name": "cell-phones"} + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.category.refresh_from_db() - self.assertEqual(self.category.name, 'cell-phones') + self.assertEqual(self.category.name, "cell-phones") class AssetModelAPITests(RalphAPITestCase): @@ -520,43 +470,39 @@ def setUp(self): self.asset_model = DataCenterAssetModelFactory() def test_get_asset_model_list(self): - url = reverse('assetmodel-list') - response = self.client.get(url, format='json') + url = reverse("assetmodel-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - self.assertEqual( - response.data['results'][0]['name'], self.asset_model.name - ) + self.assertEqual(response.data["count"], 1) + self.assertEqual(response.data["results"][0]["name"], self.asset_model.name) def test_get_asset_model_details(self): - url = reverse('assetmodel-detail', args=(self.asset_model.id,)) - response = self.client.get(url, format='json') + url = reverse("assetmodel-detail", args=(self.asset_model.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.asset_model.name) + self.assertEqual(response.data["name"], self.asset_model.name) def test_create_asset_model(self): - url = reverse('assetmodel-list') + url = reverse("assetmodel-list") data = { - 'name': 'MacBook Pro', - 'manufacturer': self.manufacturer.id, - 'type': ObjectModelType.back_office.id, + "name": "MacBook Pro", + "manufacturer": self.manufacturer.id, + "type": ObjectModelType.back_office.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(AssetModel.objects.count(), 2) - asset_model = AssetModel.objects.get(pk=response.data['id']) - self.assertEqual(asset_model.name, 'MacBook Pro') + asset_model = AssetModel.objects.get(pk=response.data["id"]) + self.assertEqual(asset_model.name, "MacBook Pro") self.assertEqual(asset_model.manufacturer, self.manufacturer) def test_patch_asset_model(self): - url = reverse('assetmodel-detail', args=(self.asset_model.id,)) - data = { - 'name': 'Iphone 6' - } - response = self.client.patch(url, data, format='json') + url = reverse("assetmodel-detail", args=(self.asset_model.id,)) + data = {"name": "Iphone 6"} + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.asset_model.refresh_from_db() - self.assertEqual(self.asset_model.name, 'Iphone 6') + self.assertEqual(self.asset_model.name, "Iphone 6") BASE_OBJECTS_FACTORIES = { @@ -578,674 +524,577 @@ def test_patch_asset_model(self): TradeMark: TradeMarkFactory, Design: DesignFactory, Patent: PatentFactory, - UtilityModel: UtilityModelFactory + UtilityModel: UtilityModelFactory, } class BaseObjectAPITests(RalphAPITestCase): def setUp(self): super().setUp() - self.bo_asset = BackOfficeAssetFactory( - barcode='12345', hostname='host1' - ) - self.bo_asset.tags.add('tag1') + self.bo_asset = BackOfficeAssetFactory(barcode="12345", hostname="host1") + self.bo_asset.tags.add("tag1") self.conf_module_1 = ConfigurationModuleFactory() self.conf_module_2 = ConfigurationModuleFactory( - parent=self.conf_module_1, name='mod1' + parent=self.conf_module_1, name="mod1" ) self.conf_class_1 = ConfigurationClassFactory( - id=999999, - module=self.conf_module_2, class_name='cls1' + id=999999, module=self.conf_module_2, class_name="cls1" ) self.dc_asset = DataCenterAssetFactory( - barcode='12543', price='9.00', - service_env__service__name='test-service', - service_env__service__uid='sc-123', - service_env__environment__name='prod', + barcode="12543", + price="9.00", + service_env__service__name="test-service", + service_env__service__uid="sc-123", + service_env__environment__name="prod", configuration_path=self.conf_class_1, ) - self.dc_asset.tags.add('tag2') - self.ip = IPAddressFactory( - ethernet=EthernetFactory(base_object=self.dc_asset) - ) - self.service = ServiceEnvironmentFactory(service__name='myservice') + self.dc_asset.tags.add("tag2") + self.ip = IPAddressFactory(ethernet=EthernetFactory(base_object=self.dc_asset)) + self.service = ServiceEnvironmentFactory(service__name="myservice") def test_get_base_objects_list(self): - url = reverse('baseobject-list') - response = self.client.get(url, format='json') + url = reverse("baseobject-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], BaseObject.objects.count()) + self.assertEqual(response.data["count"], BaseObject.objects.count()) barcodes = [ - item['barcode'] - for item in response.data['results'] - if 'barcode' in item + item["barcode"] for item in response.data["results"] if "barcode" in item ] - self.assertCountEqual(barcodes, set(['12345', '12543'])) + self.assertCountEqual(barcodes, set(["12345", "12543"])) def test_get_base_objects_list_different_type_with_custom_fields(self): - CustomField.objects.create(name='test_field') - self.dc_asset.update_custom_field('test_field', 'abc') - self.bo_asset.update_custom_field('test_field', 'def') - url = reverse('baseobject-list') - response = self.client.get(url, format='json') + CustomField.objects.create(name="test_field") + self.dc_asset.update_custom_field("test_field", "abc") + self.bo_asset.update_custom_field("test_field", "def") + url = reverse("baseobject-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) count = 0 - for item in response.data['results']: - if item['id'] == self.dc_asset.id: - self.assertEqual(item['custom_fields'], {'test_field': 'abc'}) + for item in response.data["results"]: + if item["id"] == self.dc_asset.id: + self.assertEqual(item["custom_fields"], {"test_field": "abc"}) count += 1 - if item['id'] == self.bo_asset.id: - self.assertEqual(item['custom_fields'], {'test_field': 'def'}) + if item["id"] == self.bo_asset.id: + self.assertEqual(item["custom_fields"], {"test_field": "def"}) count += 1 self.assertEqual(count, 2) def test_get_asset_model_details(self): - url = reverse('baseobject-detail', args=(self.bo_asset.id,)) - response = self.client.get(url, format='json') + url = reverse("baseobject-detail", args=(self.bo_asset.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['barcode'], '12345') + self.assertEqual(response.data["barcode"], "12345") def test_get_asset_service_simple_details(self): - url = reverse('baseobject-detail', args=(self.dc_asset.id,)) - response = self.client.get(url, format='json') + url = reverse("baseobject-detail", args=(self.dc_asset.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - service_env = response.data['service_env'] - self.assertEqual(service_env['service_uid'], 'sc-123') - self.assertEqual(service_env['service'], 'test-service') - self.assertEqual(service_env['environment'], 'prod') + service_env = response.data["service_env"] + self.assertEqual(service_env["service_uid"], "sc-123") + self.assertEqual(service_env["service"], "test-service") + self.assertEqual(service_env["environment"], "prod") def test_icontains_polymorphic(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'hostname__icontains': 'host'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"hostname__icontains": "host"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_icontains_polymorphic_with_extended_filters(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'name__startswith': 'host'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"name__startswith": "host"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_startswith_polymorphic_different_types(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'barcode__startswith': '12'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"barcode__startswith": "12"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 2) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 2) def test_lte_polymorphic(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'price__lte': '9'} - ) - ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + url = "{}?{}".format(reverse("baseobject-list"), urlencode({"price__lte": "9"})) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_is_lookup_used(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'hostname__icontains': 'no_exists_host'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), + urlencode({"hostname__icontains": "no_exists_host"}), ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 0) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 0) def test_filter_by_ip(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'ip': self.ip.address} - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"ip": self.ip.address}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_filter_by_scm_status_check_result(self): status_checks = { SCMCheckResult.scm_error: 2, SCMCheckResult.scm_ok: 1, - SCMCheckResult.check_failed: 3 + SCMCheckResult.check_failed: 3, } objects = [] - for obj_type in (CloudHostFactory, - DataCenterAssetFactory, - VirtualServerFactory): + for obj_type in ( + CloudHostFactory, + DataCenterAssetFactory, + VirtualServerFactory, + ): for _ in range(2): objects.append(obj_type()) for check_result in status_checks: for i in range(status_checks[check_result]): SCMStatusCheckFactory( - base_object=objects.pop().baseobject_ptr, - check_result=check_result + base_object=objects.pop().baseobject_ptr, check_result=check_result ) - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'scmstatuscheck__check_result': check_result.numerator} - ) - ) - response = self.client.get(url, format='json') - self.assertEqual( - len(response.data['results']), - status_checks[check_result] + url = "{}?{}".format( + reverse("baseobject-list"), + urlencode({"scmstatuscheck__check_result": check_result.numerator}), ) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), status_checks[check_result]) - for obj in response.data['results']: - self.assertIn('scmstatuscheck', obj) + for obj in response.data["results"]: + self.assertIn("scmstatuscheck", obj) self.assertEqual( - obj['scmstatuscheck']['check_result'], - check_result.raw + obj["scmstatuscheck"]["check_result"], check_result.raw ) def test_filter_by_service_uid(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'service': self.dc_asset.service_env.service.uid} - ) + url = "{}?{}".format( + reverse("baseobject-list"), + urlencode({"service": self.dc_asset.service_env.service.uid}), ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_filter_by_uid(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'uid': self.dc_asset.service_env.service.uid} - ) + url = "{}?{}".format( + reverse("baseobject-list"), + urlencode({"uid": self.dc_asset.service_env.service.uid}), ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) self.assertEqual( - response.data['results'][0]['id'], - self.dc_asset.service_env.id + response.data["results"][0]["id"], self.dc_asset.service_env.id ) def test_filter_by_service_name(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'service': self.dc_asset.service_env.service.name} - ) + url = "{}?{}".format( + reverse("baseobject-list"), + urlencode({"service": self.dc_asset.service_env.service.name}), ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_filter_by_configuration_path(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'configuration_path': 'mod1/cls1'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"configuration_path": "mod1/cls1"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) - self.assertEqual(response.data['results'][0]['id'], self.dc_asset.id) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) + self.assertEqual(response.data["results"][0]["id"], self.dc_asset.id) def test_filter_by_configuration_path_module_name(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'configuration_path__module__name': 'mod1'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), + urlencode({"configuration_path__module__name": "mod1"}), ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) - self.assertEqual(response.data['results'][0]['id'], self.dc_asset.id) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) + self.assertEqual(response.data["results"][0]["id"], self.dc_asset.id) def test_filter_by_id_startswith(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'id__startswith': '99999'} - ) - ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) - self.assertEqual( - response.data['results'][0]['id'], self.conf_class_1.id + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"id__startswith": "99999"}) ) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) + self.assertEqual(response.data["results"][0]["id"], self.conf_class_1.id) def test_filter_by_id_exact(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'id__exact': '999999'} - ) - ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) - self.assertEqual( - response.data['results'][0]['id'], self.conf_class_1.id + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"id__exact": "999999"}) ) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) + self.assertEqual(response.data["results"][0]["id"], self.conf_class_1.id) def test_tags(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - [ - ('tag', 'tag1'), ('tag', 'tag2') - ] - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode([("tag", "tag1"), ("tag", "tag2")]) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 0) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 0) - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode([('tag', 'tag1')]) - ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + url = "{}?{}".format(reverse("baseobject-list"), urlencode([("tag", "tag1")])) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_str_and_type_field(self): count = 0 for descendant in BaseObject._polymorphic_descendants: - if descendant._meta.proxy or descendant in [ - PolymorphicTestModel - ]: + if descendant._meta.proxy or descendant in [PolymorphicTestModel]: continue if not descendant._polymorphic_descendants: count += 1 obj = BASE_OBJECTS_FACTORIES[descendant]() - url = reverse('baseobject-detail', args=(obj.id,)) - response = self.client.get(url, format='json') + url = reverse("baseobject-detail", args=(obj.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( - response.data.get('__str__'), - '{}: {}'.format(obj._meta.verbose_name, str(obj)), - msg='__str__ not found (or different) for {}'.format( - descendant - ) + response.data.get("__str__"), + "{}: {}".format(obj._meta.verbose_name, str(obj)), + msg="__str__ not found (or different) for {}".format(descendant), ) self.assertEqual( - response.data.get('object_type'), obj.content_type.model + response.data.get("object_type"), obj.content_type.model ) self.assertEqual(count, len(BASE_OBJECTS_FACTORIES)) def test_filter_by_configurationclass_path(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'name__startswith': 'mod1/cls'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"name__startswith": "mod1/cls"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_filter_by_service_env_service_name(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'name__startswith': 'myserv'} - ) + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"name__startswith": "myserv"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_filter_by_cloudproject_name(self): - CloudProjectFactory(name='my-cloud-project') - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'name__startswith': 'my-cloud'} - ) + CloudProjectFactory(name="my-cloud-project") + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"name__startswith": "my-cloud"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_filter_by_cluster_name(self): - ClusterFactory(name='my-cluster') - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'name__startswith': 'my-clus'} - ) + ClusterFactory(name="my-cluster") + url = "{}?{}".format( + reverse("baseobject-list"), urlencode({"name__startswith": "my-clus"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) def test_filter_by_service_env_env_name(self): - url = '{}?{}'.format( - reverse('baseobject-list'), urlencode( - {'env': 'prod'} - ) - ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) + url = "{}?{}".format(reverse("baseobject-list"), urlencode({"env": "prod"})) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) class DCHostAPITests(RalphAPITestCase): def setUp(self): super().setUp() self.cf = CustomField.objects.create( - name='test_cf', use_as_configuration_variable=True + name="test_cf", use_as_configuration_variable=True ) # BO asset isn't DC Host - will be skipped in API - self.bo_asset = BackOfficeAssetFactory( - barcode='12345', hostname='host1' - ) + self.bo_asset = BackOfficeAssetFactory(barcode="12345", hostname="host1") self.conf_module_1 = ConfigurationModuleFactory() self.conf_module_2 = ConfigurationModuleFactory( - parent=self.conf_module_1, name='ralph' + parent=self.conf_module_1, name="ralph" ) self.conf_class_1 = ConfigurationClassFactory( - module=self.conf_module_2, class_name='cls1' + module=self.conf_module_2, class_name="cls1" ) self.dc_asset = DataCenterAssetFullFactory( - service_env__service__name='test-service', - service_env__service__uid='sc-123', - service_env__environment__name='prod', + service_env__service__name="test-service", + service_env__service__uid="sc-123", + service_env__environment__name="prod", configuration_path=self.conf_class_1, ) - self.dc_asset.update_custom_field('test_cf', 'abc') + self.dc_asset.update_custom_field("test_cf", "abc") self.virtual = VirtualServerFullFactory( parent=self.dc_asset, - configuration_path__module__name='ralph2', - service_env__service__uid='sc-222', - service_env__environment__name='some_env', + configuration_path__module__name="ralph2", + service_env__service__uid="sc-222", + service_env__environment__name="some_env", ) - self.virtual.update_custom_field('test_cf', 'def') - se = ServiceEnvironmentFactory(service__uid='sc-333') + self.virtual.update_custom_field("test_cf", "def") + se = ServiceEnvironmentFactory(service__uid="sc-333") self.cloud_host = CloudHostFullFactory( - configuration_path__module__name='ralph3', + configuration_path__module__name="ralph3", service_env=se, parent__service_env=se, - hostname='aaaa', - hypervisor=self.dc_asset + hostname="aaaa", + hypervisor=self.dc_asset, ) - self.cloud_host.ip_addresses = ['10.20.30.40'] - self.cloud_host.update_custom_field('test_cf', 'xyz') + self.cloud_host.ip_addresses = ["10.20.30.40"] + self.cloud_host.update_custom_field("test_cf", "xyz") def test_get_dc_hosts_list(self): dc_assets = DataCenterAssetFullFactory.create_batch(20) VirtualServerFullFactory.create_batch(20, parent=dc_assets[0]) CloudHostFullFactory.create_batch(20, hypervisor=dc_assets[0]) - url = reverse('dchost-list') + "?limit=100" + url = reverse("dchost-list") + "?limit=100" with self.assertQueriesMoreOrLess(30, plus_minus=1): response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 63) + self.assertEqual(response.data["count"], 63) def test_get_dc_host_details(self): dc_asset = DataCenterAssetFullFactory() VirtualServerFullFactory.create_batch(2, parent=dc_asset) CloudHostFullFactory.create_batch(2, hypervisor=dc_asset) - url = reverse('dchost-detail', args=(dc_asset.pk,)) - response = self.client.get(url, format='json') + url = reverse("dchost-detail", args=(dc_asset.pk,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) def test_get_dc_host_cloud_host_details(self): - url = reverse('dchost-detail', args=(self.cloud_host.pk,)) - response = self.client.get(url, format='json') + url = reverse("dchost-detail", args=(self.cloud_host.pk,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.json()['hypervisor']['hostname'], self.dc_asset.hostname) + self.assertEqual( + response.json()["hypervisor"]["hostname"], self.dc_asset.hostname + ) def test_filter_by_type_dc_asset(self): - url = '{}?{}'.format( - reverse('dchost-list'), - urlencode({'object_type': 'datacenterasset'}) + url = "{}?{}".format( + reverse("dchost-list"), urlencode({"object_type": "datacenterasset"}) ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - dca = response.data['results'][0] - self.assertEqual(dca['hostname'], self.dc_asset.hostname) - self.assertEqual(len(dca['ethernet']), 3) - self.assertEqual(len(dca['ipaddresses']), 2) - self.assertCountEqual(dca['tags'], ['abc, cde', 'xyz']) - self.assertEqual(dca['configuration_path']['module']['name'], 'ralph') - self.assertEqual(dca['service_env']['service_uid'], 'sc-123') - self.assertEqual(dca['object_type'], 'datacenterasset') - self.assertEqual(dca['custom_fields'], {'test_cf': 'abc'}) - self.assertEqual(dca['configuration_variables'], {'test_cf': 'abc'}) + self.assertEqual(response.data["count"], 1) + dca = response.data["results"][0] + self.assertEqual(dca["hostname"], self.dc_asset.hostname) + self.assertEqual(len(dca["ethernet"]), 3) + self.assertEqual(len(dca["ipaddresses"]), 2) + self.assertCountEqual(dca["tags"], ["abc, cde", "xyz"]) + self.assertEqual(dca["configuration_path"]["module"]["name"], "ralph") + self.assertEqual(dca["service_env"]["service_uid"], "sc-123") + self.assertEqual(dca["object_type"], "datacenterasset") + self.assertEqual(dca["custom_fields"], {"test_cf": "abc"}) + self.assertEqual(dca["configuration_variables"], {"test_cf": "abc"}) def test_filter_by_type_virtual(self): - url = '{}?{}'.format( - reverse('dchost-list'), - urlencode({'object_type': 'virtualserver'}) + url = "{}?{}".format( + reverse("dchost-list"), urlencode({"object_type": "virtualserver"}) ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - virt = response.data['results'][0] - self.assertEqual(virt['hostname'], self.virtual.hostname) - self.assertEqual(len(virt['ethernet']), 2) - self.assertEqual(len(virt['ipaddresses']), 1) - self.assertCountEqual(virt['tags'], ['abc, cde', 'xyz']) - self.assertEqual(virt['configuration_path']['module']['name'], 'ralph2') - self.assertEqual(virt['service_env']['service_uid'], 'sc-222') - self.assertEqual(virt['object_type'], 'virtualserver') - self.assertEqual(virt['custom_fields'], {'test_cf': 'def'}) - self.assertEqual(virt['configuration_variables'], {'test_cf': 'def'}) + self.assertEqual(response.data["count"], 1) + virt = response.data["results"][0] + self.assertEqual(virt["hostname"], self.virtual.hostname) + self.assertEqual(len(virt["ethernet"]), 2) + self.assertEqual(len(virt["ipaddresses"]), 1) + self.assertCountEqual(virt["tags"], ["abc, cde", "xyz"]) + self.assertEqual(virt["configuration_path"]["module"]["name"], "ralph2") + self.assertEqual(virt["service_env"]["service_uid"], "sc-222") + self.assertEqual(virt["object_type"], "virtualserver") + self.assertEqual(virt["custom_fields"], {"test_cf": "def"}) + self.assertEqual(virt["configuration_variables"], {"test_cf": "def"}) def test_filter_by_type_cloudhost(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode({'object_type': 'cloudhost'}) + url = "{}?{}".format( + reverse("dchost-list"), urlencode({"object_type": "cloudhost"}) ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - cloud = response.data['results'][0] - self.assertEqual(cloud['hostname'], self.cloud_host.hostname) - self.assertCountEqual(cloud['tags'], ['abc, cde', 'xyz']) - self.assertEqual( - cloud['configuration_path']['module']['name'], 'ralph3' - ) - self.assertEqual(cloud['service_env']['service_uid'], 'sc-333') - self.assertEqual(cloud['object_type'], 'cloudhost') - self.assertEqual(len(cloud['ethernet']), 1) - self.assertEqual(len(cloud['ipaddresses']), 1) - self.assertEqual(cloud['custom_fields'], {'test_cf': 'xyz'}) - self.assertEqual(cloud['configuration_variables'], {'test_cf': 'xyz'}) + self.assertEqual(response.data["count"], 1) + cloud = response.data["results"][0] + self.assertEqual(cloud["hostname"], self.cloud_host.hostname) + self.assertCountEqual(cloud["tags"], ["abc, cde", "xyz"]) + self.assertEqual(cloud["configuration_path"]["module"]["name"], "ralph3") + self.assertEqual(cloud["service_env"]["service_uid"], "sc-333") + self.assertEqual(cloud["object_type"], "cloudhost") + self.assertEqual(len(cloud["ethernet"]), 1) + self.assertEqual(len(cloud["ipaddresses"]), 1) + self.assertEqual(cloud["custom_fields"], {"test_cf": "xyz"}) + self.assertEqual(cloud["configuration_variables"], {"test_cf": "xyz"}) def test_filter_by_hostname(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode({'hostname': 'aaaa'}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("dchost-list"), urlencode({"hostname": "aaaa"})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_filter_by_name(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode({'name': 'aaaa'}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("dchost-list"), urlencode({"name": "aaaa"})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_uid(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode({'service': 'sc-222'}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("dchost-list"), urlencode({"service": "sc-222"})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_filter_by_ip(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode({'ip': '10.20.30.40'}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("dchost-list"), urlencode({"ip": "10.20.30.40"})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_filter_by_configuration_path(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode( - {'configuration_path': 'ralph/cls1'} - ) + url = "{}?{}".format( + reverse("dchost-list"), urlencode({"configuration_path": "ralph/cls1"}) ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) - self.assertEqual(response.data['results'][0]['id'], self.dc_asset.id) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) + self.assertEqual(response.data["results"][0]["id"], self.dc_asset.id) def test_filter_by_configuration_path_module_name(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode( - {'configuration_path__module__name': 'ralph'} - ) + url = "{}?{}".format( + reverse("dchost-list"), + urlencode({"configuration_path__module__name": "ralph"}), ) - response = self.client.get(url, format='json') - self.assertEqual(len(response.data['results']), 1) - self.assertEqual(response.data['results'][0]['id'], self.dc_asset.id) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) + self.assertEqual(response.data["results"][0]["id"], self.dc_asset.id) def test_filter_by_env_name(self): - url = '{}?{}'.format( - reverse('dchost-list'), urlencode({'env': 'some_env'}) - ) - response = self.client.get(url, format='json') + url = "{}?{}".format(reverse("dchost-list"), urlencode({"env": "some_env"})) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_patch_dchost_virtual_server(self): new_hypervisor = DataCenterAssetFullFactory() - url = reverse('dchost-detail', args=(self.virtual.id,)) + url = reverse("dchost-detail", args=(self.virtual.id,)) data = { - 'hostname': 'new-hostname', - 'hypervisor': new_hypervisor.id, + "hostname": "new-hostname", + "hypervisor": new_hypervisor.id, } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.virtual.refresh_from_db() - self.assertEqual(self.virtual.hostname, 'new-hostname') + self.assertEqual(self.virtual.hostname, "new-hostname") self.assertEqual(self.virtual.parent.id, new_hypervisor.id) def test_patch_dchost_cloudhost(self): new_hypervisor = DataCenterAssetFullFactory() - url = reverse('dchost-detail', args=(self.cloud_host.id,)) + url = reverse("dchost-detail", args=(self.cloud_host.id,)) data = { - 'hostname': 'new-hostname', - 'hypervisor': new_hypervisor.id, + "hostname": "new-hostname", + "hypervisor": new_hypervisor.id, } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.cloud_host.refresh_from_db() - self.assertEqual(self.cloud_host.hostname, 'new-hostname') + self.assertEqual(self.cloud_host.hostname, "new-hostname") self.assertEqual(self.cloud_host.hypervisor.id, new_hypervisor.id) + class ConfigurationModuleAPITests(RalphAPITestCase): def setUp(self): super().setUp() self.conf_module_1 = ConfigurationModuleFactory() - self.conf_module_2 = ConfigurationModuleFactory( - parent=self.conf_module_1 - ) + self.conf_module_2 = ConfigurationModuleFactory(parent=self.conf_module_1) def test_get_configuration_modules_list(self): - url = reverse('configurationmodule-list') - response = self.client.get(url, format='json') + url = reverse("configurationmodule-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 2) - self.assertEqual( - response.data['results'][0]['name'], self.conf_module_1.name - ) + self.assertEqual(response.data["count"], 2) + self.assertEqual(response.data["results"][0]["name"], self.conf_module_1.name) def test_get_configuration_module_details(self): - url = reverse('configurationmodule-detail', args=(self.conf_module_1.id,)) - response = self.client.get(url, format='json') + url = reverse("configurationmodule-detail", args=(self.conf_module_1.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.conf_module_1.name) + self.assertEqual(response.data["name"], self.conf_module_1.name) self.assertTrue( - response.data['children_modules'][0].endswith( - reverse('configurationmodule-detail', args=(self.conf_module_2.id,)) + response.data["children_modules"][0].endswith( + reverse("configurationmodule-detail", args=(self.conf_module_2.id,)) ) ) def test_get_configuration_module_details_with_parent(self): - url = reverse('configurationmodule-detail', args=(self.conf_module_2.id,)) - response = self.client.get(url, format='json') + url = reverse("configurationmodule-detail", args=(self.conf_module_2.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue( - response.data['parent'].endswith( - reverse('configurationmodule-detail', args=(self.conf_module_1.id,)) + response.data["parent"].endswith( + reverse("configurationmodule-detail", args=(self.conf_module_1.id,)) ) ) def test_create_configuration_module(self): - url = reverse('configurationmodule-list') + url = reverse("configurationmodule-list") data = { - 'name': 'test_1', - 'parent': self.conf_module_2.pk, + "name": "test_1", + "parent": self.conf_module_2.pk, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(ConfigurationModule.objects.count(), 3) - conf_module = ConfigurationModule.objects.get(pk=response.data['id']) - self.assertEqual(conf_module.name, 'test_1') + conf_module = ConfigurationModule.objects.get(pk=response.data["id"]) + self.assertEqual(conf_module.name, "test_1") self.assertEqual(conf_module.parent, self.conf_module_2) def test_patch_configuration_module(self): - url = reverse('configurationmodule-detail', args=(self.conf_module_2.id,)) - data = { - 'name': 'test_2' - } - response = self.client.patch(url, data, format='json') - self.assertEqual( - response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED - ) + url = reverse("configurationmodule-detail", args=(self.conf_module_2.id,)) + data = {"name": "test_2"} + response = self.client.patch(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) class ConfigurationClassAPITests(RalphAPITestCase): def setUp(self): super().setUp() self.conf_module_1 = ConfigurationModuleFactory() - self.conf_module_2 = ConfigurationModuleFactory( - parent=self.conf_module_1 - ) + self.conf_module_2 = ConfigurationModuleFactory(parent=self.conf_module_1) self.conf_class_1 = ConfigurationClassFactory(module=self.conf_module_2) def test_get_configuration_classes_list(self): - url = reverse('configurationclass-list') - response = self.client.get(url, format='json') + url = reverse("configurationclass-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) - self.assertEqual( - response.data['results'][0]['class_name'], - self.conf_class_1.class_name - ) + self.assertEqual(response.data["count"], 1) self.assertEqual( - response.data['results'][0]['module']['id'], - self.conf_module_2.id + response.data["results"][0]["class_name"], self.conf_class_1.class_name ) self.assertEqual( - response.data['results'][0]['path'], self.conf_class_1.path + response.data["results"][0]["module"]["id"], self.conf_module_2.id ) + self.assertEqual(response.data["results"][0]["path"], self.conf_class_1.path) def test_get_configuration_class_details(self): - url = reverse('configurationclass-detail', args=(self.conf_class_1.id,)) - response = self.client.get(url, format='json') + url = reverse("configurationclass-detail", args=(self.conf_class_1.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['class_name'], - self.conf_class_1.class_name - ) - self.assertEqual(response.data['path'], self.conf_class_1.path) + self.assertEqual(response.data["class_name"], self.conf_class_1.class_name) + self.assertEqual(response.data["path"], self.conf_class_1.path) self.assertTrue( - response.data['module']['url'].endswith( - reverse('configurationmodule-detail', args=(self.conf_module_2.id,)) + response.data["module"]["url"].endswith( + reverse("configurationmodule-detail", args=(self.conf_module_2.id,)) ) ) def test_create_configuration_class(self): - url = reverse('configurationclass-list') + url = reverse("configurationclass-list") data = { - 'class_name': 'test_1', - 'module': self.conf_module_2.pk, + "class_name": "test_1", + "module": self.conf_module_2.pk, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(ConfigurationClass.objects.count(), 2) - conf_class = ConfigurationClass.objects.get(pk=response.data['id']) - self.assertEqual(conf_class.class_name, 'test_1') + conf_class = ConfigurationClass.objects.get(pk=response.data["id"]) + self.assertEqual(conf_class.class_name, "test_1") self.assertEqual(conf_class.module, self.conf_module_2) def test_patch_configuration_class(self): - url = reverse('configurationclass-detail', args=(self.conf_class_1.id,)) - data = { - 'class_name': 'test_2' - } - response = self.client.patch(url, data, format='json') - self.assertEqual( - response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED - ) + url = reverse("configurationclass-detail", args=(self.conf_class_1.id,)) + data = {"class_name": "test_2"} + response = self.client.patch(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) class EthernetAPITests(RalphAPITestCase): @@ -1256,40 +1105,42 @@ def setUp(self): self.eth2 = EthernetFactory() def test_get_list_of_ethernets(self): - url = reverse('ethernet-list') - response = self.client.get(url, format='json') + url = reverse("ethernet-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['count'], 2) + self.assertEqual(response.data["count"], 2) def test_get_ethernet_with_ip_details(self): - url = reverse('ethernet-detail', args=(self.eth.id,)) - response = self.client.get(url, format='json') + url = reverse("ethernet-detail", args=(self.eth.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['ipaddress'], { - 'id': self.ip.id, - 'address': self.ip.address, - 'hostname': self.ip.hostname, - 'dhcp_expose': self.ip.dhcp_expose, - 'is_management': self.ip.is_management, - 'url': self.get_full_url( - reverse('ipaddress-detail', args=(self.ip.id,)) - ), - 'ui_url': self.get_full_url(self.ip.get_absolute_url()) - }) + self.assertEqual( + response.data["ipaddress"], + { + "id": self.ip.id, + "address": self.ip.address, + "hostname": self.ip.hostname, + "dhcp_expose": self.ip.dhcp_expose, + "is_management": self.ip.is_management, + "url": self.get_full_url( + reverse("ipaddress-detail", args=(self.ip.id,)) + ), + "ui_url": self.get_full_url(self.ip.get_absolute_url()), + }, + ) def test_cannot_delete_when_exposed_in_dhcp(self): - url = reverse('ethernet-detail', args=(self.eth.id,)) - response = self.client.delete(url, format='json') + url = reverse("ethernet-detail", args=(self.eth.id,)) + response = self.client.delete(url, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( - 'Could not delete Ethernet when it is exposed in DHCP', - response.data + "Could not delete Ethernet when it is exposed in DHCP", response.data ) def test_filter_by_ipaddress(self): - url = '{}?ipaddress__address={}'.format( - reverse('ethernet-list'), self.ip.address + url = "{}?ipaddress__address={}".format( + reverse("ethernet-list"), self.ip.address ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) diff --git a/src/ralph/assets/tests/test_models.py b/src/ralph/assets/tests/test_models.py index 63229f258e..9cc1835a88 100644 --- a/src/ralph/assets/tests/test_models.py +++ b/src/ralph/assets/tests/test_models.py @@ -4,7 +4,7 @@ from ralph.assets.tests.factories import ( ConfigurationClassFactory, ConfigurationModuleFactory, - EthernetFactory + EthernetFactory, ) from ralph.networks.tests.factories import IPAddressFactory from ralph.tests import RalphTestCase @@ -13,30 +13,24 @@ class ConfigurationTest(RalphTestCase): def setUp(self): self.conf_module_1 = ConfigurationModuleFactory() - self.conf_module_2 = ConfigurationModuleFactory( - parent=self.conf_module_1 - ) - self.conf_module_3 = ConfigurationModuleFactory( - parent=self.conf_module_2 - ) - self.conf_class_1 = ConfigurationClassFactory( - module=self.conf_module_3 - ) + self.conf_module_2 = ConfigurationModuleFactory(parent=self.conf_module_1) + self.conf_module_3 = ConfigurationModuleFactory(parent=self.conf_module_2) + self.conf_class_1 = ConfigurationClassFactory(module=self.conf_module_3) def test_update_module_children_path(self): - self.conf_module_3.name = 'updated_name' + self.conf_module_3.name = "updated_name" self.conf_module_3.save() self.conf_class_1.refresh_from_db() self.assertTrue( - self.conf_class_1.path.startswith('updated_name'), + self.conf_class_1.path.startswith("updated_name"), ) def test_update_class_path_update(self): - self.conf_class_1.class_name = 'updated_name' + self.conf_class_1.class_name = "updated_name" self.conf_class_1.save() self.conf_class_1.refresh_from_db() - self.assertTrue(self.conf_class_1.path.endswith('updated_name')) + self.assertTrue(self.conf_class_1.path.endswith("updated_name")) class EthernetTest(RalphTestCase): @@ -59,17 +53,15 @@ def test_clear_mac_address_with_ip_with_dhcp_exposition_should_not_pass(self): self.ip1.save() self.ip1.ethernet.mac = None with self.assertRaises( - ValidationError, - msg='MAC cannot be empty if record is exposed in DHCP' + ValidationError, msg="MAC cannot be empty if record is exposed in DHCP" ): self.ip1.ethernet.clean() def test_change_mac_address_with_ip_with_dhcp_exposition_should_not_pass(self): # noqa self.ip1.dhcp_expose = True self.ip1.save() - self.ip1.ethernet.mac = '11:12:13:14:15:16' + self.ip1.ethernet.mac = "11:12:13:14:15:16" with self.assertRaises( - ValidationError, - msg='Cannot change MAC when exposing in DHCP' + ValidationError, msg="Cannot change MAC when exposing in DHCP" ): self.ip1.ethernet.clean() diff --git a/src/ralph/assets/tests/test_signals.py b/src/ralph/assets/tests/test_signals.py index a842ba544c..144be90dc5 100644 --- a/src/ralph/assets/tests/test_signals.py +++ b/src/ralph/assets/tests/test_signals.py @@ -9,12 +9,12 @@ from ralph.data_center.tests.factories import ( ClusterFactory, ConfigurationClassFactory, - DataCenterAssetFactory + DataCenterAssetFactory, ) from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue + CustomFieldValue, ) from ralph.networks.models import IPAddress from ralph.tests import RalphTestCase @@ -25,7 +25,7 @@ class TestCustomFieldChangeHandler(RalphTestCase): def setUp(self): self.custom_field_str = CustomField.objects.create( - name='test str', type=CustomFieldTypes.STRING, default_value='xyz' + name="test str", type=CustomFieldTypes.STRING, default_value="xyz" ) @unpack @@ -33,32 +33,24 @@ def setUp(self): (CloudHostFactory,), (ClusterFactory,), (DataCenterAssetFactory,), - (VirtualServerFactory,) + (VirtualServerFactory,), ) def test_should_publish_host_update_event_when_dc_host(self, m_factory): m_instance = m_factory() cfv = CustomFieldValue.objects.create( - object=m_instance, - custom_field=self.custom_field_str, - value='sample_value' + object=m_instance, custom_field=self.custom_field_str, value="sample_value" ) - with patch('ralph.assets.signals.publish_host_update') as mock: - custom_field_change( - sender=m_instance.__class__, instance=cfv - ) + with patch("ralph.assets.signals.publish_host_update") as mock: + custom_field_change(sender=m_instance.__class__, instance=cfv) mock.assert_called_once_with(m_instance) def test_should_not_publish_host_update_event_when_not_dc_host(self): bo_asset = BackOfficeAssetFactory() cfv = CustomFieldValue.objects.create( - object=bo_asset, - custom_field=self.custom_field_str, - value='sample_value' + object=bo_asset, custom_field=self.custom_field_str, value="sample_value" ) - with patch('ralph.assets.signals.publish_host_update') as mock: - custom_field_change( - sender=bo_asset.__class__, instance=cfv - ) + with patch("ralph.assets.signals.publish_host_update") as mock: + custom_field_change(sender=bo_asset.__class__, instance=cfv) self.assertFalse(mock.called) @@ -69,17 +61,12 @@ class TestRelatedObjectsChangeHandler(TransactionTestCase): (CloudHostFactory,), (ClusterFactory,), (DataCenterAssetFactory,), - (VirtualServerFactory,) + (VirtualServerFactory,), ) - def test_should_publish_host_update_when_ipaddress_added( - self, model_factory - ): + def test_should_publish_host_update_when_ipaddress_added(self, model_factory): model_instance = model_factory() - with patch('ralph.data_center.publishers.publish_host_update') as mock: - IPAddress.objects.create( - address='10.20.30.40', - base_object=model_instance - ) + with patch("ralph.data_center.publishers.publish_host_update") as mock: + IPAddress.objects.create(address="10.20.30.40", base_object=model_instance) # will be called 2 times: for Ethernet and for IPAddress mock.assert_called_with(model_instance) @@ -88,17 +75,12 @@ def test_should_publish_host_update_when_ipaddress_added( (CloudHostFactory,), (ClusterFactory,), (DataCenterAssetFactory,), - (VirtualServerFactory,) + (VirtualServerFactory,), ) - def test_should_publish_host_update_when_ethernet_added( - self, model_factory - ): + def test_should_publish_host_update_when_ethernet_added(self, model_factory): model_instance = model_factory() - with patch('ralph.data_center.publishers.publish_host_update') as mock: - Ethernet.objects.create( - mac='aa:bb:cc:dd:ee:ff', - base_object=model_instance - ) + with patch("ralph.data_center.publishers.publish_host_update") as mock: + Ethernet.objects.create(mac="aa:bb:cc:dd:ee:ff", base_object=model_instance) mock.assert_called_once_with(model_instance) @unpack @@ -106,17 +88,15 @@ def test_should_publish_host_update_when_ethernet_added( (CloudHostFactory,), (ClusterFactory,), (DataCenterAssetFactory,), - (VirtualServerFactory,) + (VirtualServerFactory,), ) - def test_should_publish_host_update_when_conf_class_changed( - self, model_factory - ): + def test_should_publish_host_update_when_conf_class_changed(self, model_factory): conf_class = ConfigurationClassFactory() model_factory.create_batch(2, configuration_path=conf_class) - with patch('ralph.data_center.publishers.publish_host_update') as mock: + with patch("ralph.data_center.publishers.publish_host_update") as mock: # refresh instance to not fall into post_commit single event conf_class = ConfigurationClass.objects.get(pk=conf_class.pk) - conf_class.name = 'another_class' + conf_class.name = "another_class" conf_class.save() self.assertEqual(mock.call_count, 2) @@ -125,14 +105,12 @@ def test_should_publish_host_update_when_conf_class_changed( (CloudHostFactory,), (ClusterFactory,), (DataCenterAssetFactory,), - (VirtualServerFactory,) + (VirtualServerFactory,), ) - def test_should_publish_host_update_when_conf_module_changed( - self, model_factory - ): + def test_should_publish_host_update_when_conf_module_changed(self, model_factory): conf_class = ConfigurationClassFactory() model_factory.create_batch(2, configuration_path=conf_class) - with patch('ralph.data_center.publishers.publish_host_update') as mock: - conf_class.module.name = 'another_module' + with patch("ralph.data_center.publishers.publish_host_update") as mock: + conf_class.module.name = "another_module" conf_class.module.save() self.assertEqual(mock.call_count, 2) diff --git a/src/ralph/assets/tests/test_subscribers.py b/src/ralph/assets/tests/test_subscribers.py index eb37aa72fb..548ac91d47 100644 --- a/src/ralph/assets/tests/test_subscribers.py +++ b/src/ralph/assets/tests/test_subscribers.py @@ -9,139 +9,120 @@ from ralph.accounts.tests.factories import UserFactory from ralph.assets.models import Service from ralph.assets.subscribers import ACTION_TYPE -from ralph.assets.tests.factories import ( - ServiceEnvironmentFactory, - ServiceFactory -) +from ralph.assets.tests.factories import ServiceEnvironmentFactory, ServiceFactory from ralph.data_center.tests.factories import DataCenterAssetFactory class ServiceSubscribersTestCase(TestCase): - def setUp(self): super().setUp() for i in range(1, 4): - UserFactory(username='business_user{}'.format(i)) - UserFactory(username='technical_user{}'.format(i)) + UserFactory(username="business_user{}".format(i)) + UserFactory(username="technical_user{}".format(i)) def _make_request(self, event_data, subscriber_name): response = self.client.post( reverse( - 'hermes-event-subscriber', - kwargs={ - 'subscriber_name': subscriber_name - } + "hermes-event-subscriber", kwargs={"subscriber_name": subscriber_name} ), json.dumps(event_data), content_type="application/json", - follow=False + follow=False, ) return response def test_update_service_when_service_does_not_exist(self): data = { - 'uid': 'sc-001', - 'name': 'TestName', - 'status': 'Active', - 'isActive': True, - 'environments': ['prod', 'dev'], - 'businessOwners': [{'username': 'business_user1'}], - 'technicalOwners': [{'username': 'technical_user2'}], - 'area': {'name': 'new area', 'profitCenter': 'test-PC'}, + "uid": "sc-001", + "name": "TestName", + "status": "Active", + "isActive": True, + "environments": ["prod", "dev"], + "businessOwners": [{"username": "business_user1"}], + "technicalOwners": [{"username": "technical_user2"}], + "area": {"name": "new area", "profitCenter": "test-PC"}, } - response = self._make_request( - data, settings.HERMES_SERVICE_TOPICS['CREATE'] - ) + response = self._make_request(data, settings.HERMES_SERVICE_TOPICS["CREATE"]) self.assertEqual(response.status_code, 204) - service = Service.objects.get(uid='sc-001') + service = Service.objects.get(uid="sc-001") self.assertTrue(service.active) - self.assertEqual(service.name, 'TestName') - self.assertEqual(service.business_segment.name, 'new area') - self.assertEqual(service.profit_center.name, 'test-PC') + self.assertEqual(service.name, "TestName") + self.assertEqual(service.business_segment.name, "new area") + self.assertEqual(service.profit_center.name, "test-PC") self.assertCountEqual( - ['prod', 'dev'], - [env.name for env in service.environments.all()] + ["prod", "dev"], [env.name for env in service.environments.all()] ) self.assertCountEqual( - ['business_user1'], - [user.username for user in service.business_owners.all()] + ["business_user1"], + [user.username for user in service.business_owners.all()], ) self.assertCountEqual( - ['technical_user2'], - [user.username for user in service.technical_owners.all()] + ["technical_user2"], + [user.username for user in service.technical_owners.all()], ) def test_update_service_when_service_exist(self): service = ServiceFactory( - business_segment__name='existing area', - profit_center__name='existing PC', - ) - service.business_owners.add(UserFactory(username='business_user1')) - service.technical_owners.add(UserFactory(username='technical_user2')) - ServiceEnvironmentFactory( - service=service, environment__name='prod' + business_segment__name="existing area", + profit_center__name="existing PC", ) + service.business_owners.add(UserFactory(username="business_user1")) + service.technical_owners.add(UserFactory(username="technical_user2")) + ServiceEnvironmentFactory(service=service, environment__name="prod") data = { - 'uid': service.uid, - 'name': 'New name', - 'status': 'Active', - 'isActive': True, - 'environments': ['dev'], - 'businessOwners': [{'username': 'business_user3'}], - 'technicalOwners': [{'username': 'technical_user3'}], - 'area': {'name': 'new area', 'profitCenter': 'new-PC'}, + "uid": service.uid, + "name": "New name", + "status": "Active", + "isActive": True, + "environments": ["dev"], + "businessOwners": [{"username": "business_user3"}], + "technicalOwners": [{"username": "technical_user3"}], + "area": {"name": "new area", "profitCenter": "new-PC"}, } - response = self._make_request( - data, settings.HERMES_SERVICE_TOPICS['UPDATE'] - ) + response = self._make_request(data, settings.HERMES_SERVICE_TOPICS["UPDATE"]) self.assertEqual(response.status_code, 204) service.refresh_from_db() - self.assertEqual(service.name, 'New name') - self.assertEqual(service.business_segment.name, 'new area') - self.assertEqual(service.profit_center.name, 'new-PC') + self.assertEqual(service.name, "New name") + self.assertEqual(service.business_segment.name, "new area") + self.assertEqual(service.profit_center.name, "new-PC") + self.assertCountEqual(["dev"], [env.name for env in service.environments.all()]) self.assertCountEqual( - ['dev'], - [env.name for env in service.environments.all()] + ["business_user3"], + [user.username for user in service.business_owners.all()], ) self.assertCountEqual( - ['business_user3'], - [user.username for user in service.business_owners.all()] - ) - self.assertCountEqual( - ['technical_user3'], - [user.username for user in service.technical_owners.all()] + ["technical_user3"], + [user.username for user in service.technical_owners.all()], ) - @patch('ralph.assets.subscribers.logger') + @patch("ralph.assets.subscribers.logger") def test_update_service_environment_when_environment_assigned_to_object( self, mock_logger ): service = ServiceFactory(active=True) service_env = ServiceEnvironmentFactory( - service=service, environment__name='prod' + service=service, environment__name="prod" ) DataCenterAssetFactory(service_env=service_env) data = { - 'uid': service.uid, - 'name': 'New name', - 'status': 'Active', - 'isActive': False, - 'environments': ['dev'], - 'businessOwners': [{'username': 'business_user3'}], - 'technicalOwners': [{'username': 'technical_user3'}] + "uid": service.uid, + "name": "New name", + "status": "Active", + "isActive": False, + "environments": ["dev"], + "businessOwners": [{"username": "business_user3"}], + "technicalOwners": [{"username": "technical_user3"}], } - response = self._make_request( - data, settings.HERMES_SERVICE_TOPICS['UPDATE'] - ) + response = self._make_request(data, settings.HERMES_SERVICE_TOPICS["UPDATE"]) self.assertEqual(response.status_code, 204) service.refresh_from_db() mock_logger.error.assert_called_with( - 'Can not delete service environment - it has assigned some base objects', # noqa: E501 + "Can not delete service environment - it has assigned some base objects", # noqa: E501 extra={ - 'action_type': ACTION_TYPE, - 'service_uid': service.uid, - 'service_name': service.name - } + "action_type": ACTION_TYPE, + "service_uid": service.uid, + "service_name": service.name, + }, ) service.refresh_from_db() self.assertTrue(service.active) @@ -149,46 +130,42 @@ def test_update_service_environment_when_environment_assigned_to_object( def test_delete_with_valid_event_data(self): service = ServiceFactory(active=True) data = { - 'uid': service.uid, - 'name': 'Service name', - 'status': 'Inactive', - 'isActive': False, - 'environments': ['dev'], - 'businessOwners': [{'username': 'business_user1'}], - 'technicalOwners': [{'username': 'technical_user1'}] + "uid": service.uid, + "name": "Service name", + "status": "Inactive", + "isActive": False, + "environments": ["dev"], + "businessOwners": [{"username": "business_user1"}], + "technicalOwners": [{"username": "technical_user1"}], } - response = self._make_request( - data, settings.HERMES_SERVICE_TOPICS['DELETE'] - ) + response = self._make_request(data, settings.HERMES_SERVICE_TOPICS["DELETE"]) self.assertEqual(response.status_code, 204) service.refresh_from_db() self.assertFalse(service.active) - @patch('ralph.assets.subscribers.logger') + @patch("ralph.assets.subscribers.logger") def test_delete_service_when_service_assigned_to_object(self, mock_logger): service = ServiceFactory(active=True) service_env = ServiceEnvironmentFactory(service=service) DataCenterAssetFactory(service_env=service_env) data = { - 'uid': service.uid, - 'name': 'Service name', - 'status': 'Inactive', - 'isActive': False, - 'environments': ['dev'], - 'businessOwners': [{'username': 'business_user'}], - 'technicalOwners': [{'username': 'technical_user'}] + "uid": service.uid, + "name": "Service name", + "status": "Inactive", + "isActive": False, + "environments": ["dev"], + "businessOwners": [{"username": "business_user"}], + "technicalOwners": [{"username": "technical_user"}], } - response = self._make_request( - data, settings.HERMES_SERVICE_TOPICS['DELETE'] - ) + response = self._make_request(data, settings.HERMES_SERVICE_TOPICS["DELETE"]) self.assertEqual(response.status_code, 204) mock_logger.error.assert_called_with( - 'Can not delete service - it has assigned some base objects', + "Can not delete service - it has assigned some base objects", extra={ - 'action_type': ACTION_TYPE, - 'service_uid': data['uid'], - 'service_name': data['name'] - } + "action_type": ACTION_TYPE, + "service_uid": data["uid"], + "service_name": data["name"], + }, ) service.refresh_from_db() self.assertTrue(service.active) diff --git a/src/ralph/assets/utils.py b/src/ralph/assets/utils.py index 34111089c4..a1bc83a156 100644 --- a/src/ralph/assets/utils.py +++ b/src/ralph/assets/utils.py @@ -6,15 +6,25 @@ class DNSaaSPublisherMixin: """Generate data formatted for DNSaaS auto txt update""" + def get_auto_txt_data(self): data = [] for purpose_name, content in ( - ('class_name', self.configuration_path.class_name if self.configuration_path else ''), # noqa - ('module_name', self.configuration_path.module.name if self.configuration_path else ''), # noqa - ('configuration_path', self.configuration_path.path if self.configuration_path else ''), # noqa - ('service_env', str(self.service_env) if self.service_env else ''), # noqa - ('model', str(self.model) if self.model else ''), - ('location', ' / '.join(self.get_location() or [])), + ( + "class_name", + self.configuration_path.class_name if self.configuration_path else "", + ), # noqa + ( + "module_name", + self.configuration_path.module.name if self.configuration_path else "", + ), # noqa + ( + "configuration_path", + self.configuration_path.path if self.configuration_path else "", + ), # noqa + ("service_env", str(self.service_env) if self.service_env else ""), # noqa + ("model", str(self.model) if self.model else ""), + ("location", " / ".join(self.get_location() or [])), ): purpose = settings.DNSAAS_AUTO_TXT_RECORD_PURPOSE_MAP.get( purpose_name, None @@ -22,16 +32,13 @@ def get_auto_txt_data(self): if not purpose or not content: continue update_def = { - 'ips': [ - ip.address for ip in self.ipaddresses if - not ip.is_management - ], - 'purpose': purpose, - 'content': content, + "ips": [ip.address for ip in self.ipaddresses if not ip.is_management], + "purpose": purpose, + "content": content, } service = self.service if service: - update_def['service_uid'] = service.uid + update_def["service_uid"] = service.uid data.append(update_def) return data @@ -85,6 +92,7 @@ def get_host_content_types(): """ from ralph.data_center.models import Cluster, DataCenterAsset from ralph.virtual.models import CloudHost, VirtualServer + return ContentType.objects.get_for_models( Cluster, DataCenterAsset, VirtualServer, CloudHost ).values() diff --git a/src/ralph/assets/views.py b/src/ralph/assets/views.py index 9ebf25c303..336a1d8f01 100644 --- a/src/ralph/assets/views.py +++ b/src/ralph/assets/views.py @@ -7,54 +7,51 @@ Ethernet, FibreChannelCard, Memory, - Processor + Processor, ) from ralph.networks.forms import EthernetLockDeleteForm, NetworkInlineFormset class ComponentsAdminView(RalphDetailViewAdmin): - icon = 'folder' - name = 'components' - label = _('Components') - url_name = 'components' + icon = "folder" + name = "components" + label = _("Components") + url_name = "components" class MemoryInline(RalphTabularInline): model = Memory - fields = ('model_name', 'size', 'speed') + fields = ("model_name", "size", "speed") extra = 1 class FibreChannelCardInline(RalphTabularInline): model = FibreChannelCard fields = ( - 'model_name', - 'speed', - 'wwn', - 'firmware_version', + "model_name", + "speed", + "wwn", + "firmware_version", ) extra = 1 class ProcessorInline(RalphTabularInline): model = Processor - fields = ( - 'model_name', - 'speed', - 'cores', - 'logical_cores' - ) + fields = ("model_name", "speed", "cores", "logical_cores") extra = 1 class DiskInline(RalphTabularInline): model = Disk fields = ( - 'model_name', 'size', 'serial_number', 'slot', 'firmware_version', + "model_name", + "size", + "serial_number", + "slot", + "firmware_version", ) extra = 1 class EthernetInline(RalphTabularInline): model = Ethernet - fields = ( - 'mac', 'model_name', 'label', 'speed' - ) + fields = ("mac", "model_name", "label", "speed") extra = 1 formset = NetworkInlineFormset form = EthernetLockDeleteForm diff --git a/src/ralph/attachments/admin.py b/src/ralph/attachments/admin.py index 9787e23797..6fb8c0c270 100644 --- a/src/ralph/attachments/admin.py +++ b/src/ralph/attachments/admin.py @@ -1,4 +1,3 @@ - from ralph.attachments.views import AttachmentsView @@ -6,15 +5,18 @@ class AttachmentsMixin(object): """ Mixin add new URL to admin for download file. """ + def __init__(self, *args, **kwargs): # create unique AttachmentsView subclass for each descendant admin site # this prevents conflicts between urls etc. # See ralph.admin.extra.RalphExtraViewMixin.post_register for details if self.change_views is None: self.change_views = [] - self.change_views.append(type( - '{}AttachmentsView'.format(self.__class__.__name__), - (AttachmentsView,), - {} - )) + self.change_views.append( + type( + "{}AttachmentsView".format(self.__class__.__name__), + (AttachmentsView,), + {}, + ) + ) super().__init__(*args, **kwargs) diff --git a/src/ralph/attachments/forms.py b/src/ralph/attachments/forms.py index abd14fc50b..a2600b3a60 100644 --- a/src/ralph/attachments/forms.py +++ b/src/ralph/attachments/forms.py @@ -8,19 +8,16 @@ class ChangeAttachmentWidget(forms.ClearableFileInput): - template_with_initial = ( - '
    %(input_text)s: %(input)s
    ' - ) + template_with_initial = "
    %(input_text)s: %(input)s
    " class AttachmentForm(RequestModelForm): - class Meta: - fields = ['file', 'description'] + fields = ["file", "description"] model = Attachment widgets = { - 'file': ChangeAttachmentWidget(), - 'description': forms.Textarea(attrs={'rows': 2, 'cols': 30}), + "file": ChangeAttachmentWidget(), + "description": forms.Textarea(attrs={"rows": 2, "cols": 30}), } def save(self, commit=True): @@ -41,13 +38,11 @@ def save(self, commit=True): if attachment: # if file with the same MD5 is already saved, reuse it and # attach it parent object - content_type = get_content_type_for_model( - self._parent_object._meta.model - ) + content_type = get_content_type_for_model(self._parent_object._meta.model) if not AttachmentItem.objects.filter( content_type=content_type, object_id=self._parent_object.pk, - attachment__md5=md5 + attachment__md5=md5, ).exists(): AttachmentItem.objects.attach( self._parent_object.pk, content_type, [attachment] @@ -58,16 +53,18 @@ def save(self, commit=True): messages.add_message( self._request, messages.WARNING, - _(( - 'Another attachment with the same signature ({}) is ' - 'already attached to this object' - ).format(attachment.original_filename)) + _( + ( + "Another attachment with the same signature ({}) is " + "already attached to this object" + ).format(attachment.original_filename) + ), ) return obj.md5 = md5 obj.uploaded_by = self._request.user - file = self.cleaned_data.get('file', None) - if file and hasattr(file, 'content_type'): + file = self.cleaned_data.get("file", None) + if file and hasattr(file, "content_type"): obj.mime_type = file.content_type obj.save() return obj diff --git a/src/ralph/attachments/helpers.py b/src/ralph/attachments/helpers.py index 8cc745ace8..a4698d27f2 100644 --- a/src/ralph/attachments/helpers.py +++ b/src/ralph/attachments/helpers.py @@ -4,7 +4,7 @@ from uuid import uuid4 -def get_file_path(instance, filename, default_dir='attachments'): +def get_file_path(instance, filename, default_dir="attachments"): """Generates pseudo-random file path. Function generate hard to guess file path based on arguments and @@ -21,11 +21,11 @@ def get_file_path(instance, filename, default_dir='attachments'): {attachment}/{1st_uuid_char}/{2nd_uuid_char}/{uuid}.{ext} """ ext = os.path.splitext(filename)[1] - name = ''.join([str(uuid4()), ext]) + name = "".join([str(uuid4()), ext]) return os.path.join(default_dir, name[:1], name[1:2], name) -def add_attachment_from_disk(objs, local_path_to_file, owner, description=''): +def add_attachment_from_disk(objs, local_path_to_file, owner, description=""): """Create attachment from absolute file path. Function create and returns attachment object with file from local path. @@ -50,12 +50,11 @@ def add_attachment_from_disk(objs, local_path_to_file, owner, description=''): >>> add_attachment_from_disk(foo, '/etc/passwd', root) """ from ralph.attachments.models import Attachment, AttachmentItem - attachment = Attachment.objects.create_from_file_path( - local_path_to_file, owner - ) + + attachment = Attachment.objects.create_from_file_path(local_path_to_file, owner) mime_type = mimetypes.guess_type(local_path_to_file)[0] if mime_type is None: - mime_type = 'application/octet-stream' + mime_type = "application/octet-stream" attachment.mime_type = mime_type attachment.description = description attachment.save() diff --git a/src/ralph/attachments/migrations/0001_initial.py b/src/ralph/attachments/migrations/0001_initial.py index cea349c0fe..29c04ce282 100644 --- a/src/ralph/attachments/migrations/0001_initial.py +++ b/src/ralph/attachments/migrations/0001_initial.py @@ -8,38 +8,91 @@ class Migration(migrations.Migration): - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), + ("contenttypes", "0002_remove_content_type_name"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='Attachment', + name="Attachment", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('md5', models.CharField(unique=True, max_length=32)), - ('original_filename', models.CharField(max_length=255)), - ('file', models.FileField(upload_to=ralph.attachments.helpers.get_file_path, max_length=255)), - ('mime_type', models.CharField(default='application/octet-stream', max_length=100)), - ('description', models.TextField(blank=True)), - ('uploaded_by', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ("md5", models.CharField(unique=True, max_length=32)), + ("original_filename", models.CharField(max_length=255)), + ( + "file", + models.FileField( + upload_to=ralph.attachments.helpers.get_file_path, + max_length=255, + ), + ), + ( + "mime_type", + models.CharField( + default="application/octet-stream", max_length=100 + ), + ), + ("description", models.TextField(blank=True)), + ( + "uploaded_by", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, - 'ordering': ('-modified', '-created'), + "abstract": False, + "ordering": ("-modified", "-created"), }, ), migrations.CreateModel( - name='AttachmentItem', + name="AttachmentItem", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('object_id', models.PositiveIntegerField()), - ('attachment', models.ForeignKey(to='attachments.Attachment', related_name='items', on_delete=django.db.models.deletion.CASCADE)), - ('content_type', models.ForeignKey(to='contenttypes.ContentType', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("object_id", models.PositiveIntegerField()), + ( + "attachment", + models.ForeignKey( + to="attachments.Attachment", + related_name="items", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "content_type", + models.ForeignKey( + to="contenttypes.ContentType", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], ), ] diff --git a/src/ralph/attachments/migrations/0002_auto_20151125_1354.py b/src/ralph/attachments/migrations/0002_auto_20151125_1354.py index 613a2288b3..9eaa754837 100644 --- a/src/ralph/attachments/migrations/0002_auto_20151125_1354.py +++ b/src/ralph/attachments/migrations/0002_auto_20151125_1354.py @@ -5,20 +5,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('attachments', '0001_initial'), + ("attachments", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='attachment', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="attachment", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='attachment', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="attachment", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), ] diff --git a/src/ralph/attachments/migrations/0003_auto_20160121_1346.py b/src/ralph/attachments/migrations/0003_auto_20160121_1346.py index 510c99e839..feceb1684a 100644 --- a/src/ralph/attachments/migrations/0003_auto_20160121_1346.py +++ b/src/ralph/attachments/migrations/0003_auto_20160121_1346.py @@ -1,47 +1,41 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations from ralph.admin.helpers import get_content_type_for_model def migrate_attachment_item(apps, schema_editor): - AttachmentItem = apps.get_model('attachments', 'AttachmentItem') + AttachmentItem = apps.get_model("attachments", "AttachmentItem") for item in AttachmentItem.objects.all(): - model = apps.get_model( - item.content_type.app_label, item.content_type.model - ) + model = apps.get_model(item.content_type.app_label, item.content_type.model) item.content_type_id = get_content_type_for_model(model).id item.save() def unload_migrate_attachment_item(apps, schema_editor): - AttachmentItem = apps.get_model('attachments', 'AttachmentItem') - BaseObject = apps.get_model('assets', 'BaseObject') - ContentType = apps.get_model('contenttypes', 'ContentType') + AttachmentItem = apps.get_model("attachments", "AttachmentItem") + BaseObject = apps.get_model("assets", "BaseObject") + ContentType = apps.get_model("contenttypes", "ContentType") bo_content_type = ContentType.objects.get_for_model(BaseObject) for item in AttachmentItem.objects.filter(content_type=bo_content_type): - content_type = BaseObject.objects.get( - pk=item.object_id - ).content_type + content_type = BaseObject.objects.get(pk=item.object_id).content_type item.content_type = content_type item.save() class Migration(migrations.Migration): - dependencies = [ - ('attachments', '0002_auto_20151125_1354'), - ('back_office', '0003_auto_20151204_0758'), - ('data_center', '0004_auto_20151204_0758'), - ('domains', '0002_auto_20151125_1354'), - ('licences', '0002_auto_20151204_1325'), - ('supports', '0005_auto_20160105_1222'), + ("attachments", "0002_auto_20151125_1354"), + ("back_office", "0003_auto_20151204_0758"), + ("data_center", "0004_auto_20151204_0758"), + ("domains", "0002_auto_20151125_1354"), + ("licences", "0002_auto_20151204_1325"), + ("supports", "0005_auto_20160105_1222"), ] operations = [ migrations.RunPython( - migrate_attachment_item, - reverse_code=unload_migrate_attachment_item + migrate_attachment_item, reverse_code=unload_migrate_attachment_item ), ] diff --git a/src/ralph/attachments/models.py b/src/ralph/attachments/models.py index f7af17fda8..11fde3ab45 100644 --- a/src/ralph/attachments/models.py +++ b/src/ralph/attachments/models.py @@ -35,7 +35,7 @@ def create_from_file_path(self, file_path, uploaded_by): attachment.uploaded_by = uploaded_by filename = os.path.basename(file_path) attachment.original_filename = filename - with open(file_path, 'rb') as f: + with open(file_path, "rb") as f: content = ContentFile(f.read()) attachment.file.save(filename, content, save=True) return attachment @@ -52,9 +52,13 @@ def get_items_for_object(self, obj): [] """ content_type = get_content_type_for_model(obj) - return self.get_queryset().select_related('attachment').filter( - object_id=obj.pk, - content_type=content_type, + return ( + self.get_queryset() + .select_related("attachment") + .filter( + object_id=obj.pk, + content_type=content_type, + ) ) def attach(self, pk, content_type, attachments): @@ -63,11 +67,13 @@ def attach(self, pk, content_type, attachments): """ new_items = [] for attachment in attachments: - new_items.append(self.model( - content_type=content_type, - object_id=pk, - attachment=attachment, - )) + new_items.append( + self.model( + content_type=content_type, + object_id=pk, + attachment=attachment, + ) + ) if new_items: self.bulk_create(new_items) @@ -103,6 +109,7 @@ class Attachment(TimeStampMixin, models.Model): * description - e.g., description of file's content or some comment, * uploaded_by - the user who added attachment. """ + md5 = models.CharField(max_length=32, unique=True) original_filename = models.CharField( max_length=255, @@ -112,7 +119,7 @@ class Attachment(TimeStampMixin, models.Model): mime_type = models.CharField( max_length=100, unique=False, - default='application/octet-stream', + default="application/octet-stream", ) description = models.TextField(blank=True) uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) @@ -120,7 +127,7 @@ class Attachment(TimeStampMixin, models.Model): objects = AttachmentManager() def __str__(self): - return '{} ({}) uploaded by {}'.format( + return "{} ({}) uploaded by {}".format( self.original_filename, self.mime_type, self.uploaded_by ) @@ -157,8 +164,8 @@ def _safe_filename(filename): >>> Attachment._safe_filename('injection.txt?q=alert("Ha!")') 'injection.txtqalert(Ha)'' """ - allowed = '-_.() ' + string.ascii_letters + string.digits - return ''.join(filter(lambda x: x in allowed, unidecode(filename))) + allowed = "-_.() " + string.ascii_letters + string.digits + return "".join(filter(lambda x: x in allowed, unidecode(filename))) class AttachmentItem(models.Model): @@ -166,14 +173,17 @@ class AttachmentItem(models.Model): This model is bridge between attachment and content type - with this model we can add one attachment and link with many content types. """ - attachment = models.ForeignKey(Attachment, related_name='items', on_delete=models.CASCADE) + + attachment = models.ForeignKey( + Attachment, related_name="items", on_delete=models.CASCADE + ) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() - content_object = fields.GenericForeignKey('content_type', 'object_id') + content_object = fields.GenericForeignKey("content_type", "object_id") objects = AttachmentItemManager() def __str__(self): - return '{} {}: {}'.format( + return "{} {}: {}".format( self.attachment.mime_type, self.content_type, self.object_id ) diff --git a/src/ralph/attachments/tests/__init__.py b/src/ralph/attachments/tests/__init__.py index ef34ca59c8..ee00ea4ca2 100644 --- a/src/ralph/attachments/tests/__init__.py +++ b/src/ralph/attachments/tests/__init__.py @@ -10,17 +10,17 @@ from ralph.attachments.models import Attachment, AttachmentItem -User = apps.get_model(*settings.AUTH_USER_MODEL.split('.')) +User = apps.get_model(*settings.AUTH_USER_MODEL.split(".")) class AttachmentsTestCase(TestCase): def create_attachment_for_object( - self, obj, filename=None, user=None, content=b'some content' + self, obj, filename=None, user=None, content=b"some content" ): if not user: - user, _ = User.objects.get_or_create(username='tester') + user, _ = User.objects.get_or_create(username="tester") if not filename: - filename = 'test' + filename = "test" content += str.encode(str(random.random())) attachment = Attachment.objects.create( file=SimpleUploadedFile(filename, content), diff --git a/src/ralph/attachments/tests/test_models.py b/src/ralph/attachments/tests/test_models.py index b8f7b04144..0becff0b6f 100644 --- a/src/ralph/attachments/tests/test_models.py +++ b/src/ralph/attachments/tests/test_models.py @@ -9,32 +9,28 @@ class AttachmentTest(AttachmentsTestCase): def test_saved_original_name(self): - obj = Foo.objects.create(bar='test') - filename = 'test.txt' + obj = Foo.objects.create(bar="test") + filename = "test.txt" item = self.create_attachment_for_object(obj, filename=filename) - self.assertFalse( - item.attachment.file == item.attachment.original_filename - ) + self.assertFalse(item.attachment.file == item.attachment.original_filename) self.assertEqual(filename, item.attachment.original_filename) def test_get_all_attachments_for_object(self): - self.create_attachment_for_object(Foo.objects.create(bar='test')) + self.create_attachment_for_object(Foo.objects.create(bar="test")) self.create_attachment_for_object(TestManufacturer.objects.create()) - obj = Foo.objects.create(bar='test') + obj = Foo.objects.create(bar="test") self.create_attachment_for_object(obj) self.create_attachment_for_object(obj) - self.assertEqual( - AttachmentItem.objects.get_items_for_object(obj).count(), 2 - ) + self.assertEqual(AttachmentItem.objects.get_items_for_object(obj).count(), 2) def test_create_from_file_path_file_name(self): with TemporaryDirectory() as tmp_dir_name: - file_path = os.path.join(tmp_dir_name, 'łóźć.pdf') - with open(file_path, 'w+') as f: - f.write('content') + file_path = os.path.join(tmp_dir_name, "łóźć.pdf") + with open(file_path, "w+") as f: + f.write("content") attachment = Attachment.objects.create_from_file_path( file_path, UserFactory() ) attachment.save() - self.assertEqual(attachment.original_filename, 'lozc.pdf') + self.assertEqual(attachment.original_filename, "lozc.pdf") diff --git a/src/ralph/attachments/urls.py b/src/ralph/attachments/urls.py index 4d9c728519..414e59b819 100644 --- a/src/ralph/attachments/urls.py +++ b/src/ralph/attachments/urls.py @@ -4,8 +4,8 @@ urlpatterns = [ url( - r'^attachment/(?P\d+)-(?P.+)', + r"^attachment/(?P\d+)-(?P.+)", ServeAttachment.as_view(), - name='serve_attachment' + name="serve_attachment", ), ] diff --git a/src/ralph/attachments/utils.py b/src/ralph/attachments/utils.py index 46a1cc7d94..329486a112 100644 --- a/src/ralph/attachments/utils.py +++ b/src/ralph/attachments/utils.py @@ -6,15 +6,15 @@ def send_transition_attachments_to_user( requester, transition_id, context_func, **kwargs ): - if kwargs.get('attachments'): + if kwargs.get("attachments"): transition = Transition.objects.get(pk=transition_id) context = context_func(transition_name=transition.name) email = EmailMessage( subject=context.subject, body=context.body, from_email=context.from_email, - to=[requester.email] + to=[requester.email], ) - for attachment in kwargs['attachments']: + for attachment in kwargs["attachments"]: email.attach_file(attachment.file.path) email.send() diff --git a/src/ralph/attachments/views.py b/src/ralph/attachments/views.py index ec23aa3624..ec40da4766 100644 --- a/src/ralph/attachments/views.py +++ b/src/ralph/attachments/views.py @@ -13,11 +13,11 @@ class AttachmentsView(RalphDetailView): - icon = 'paperclip' - name = 'attachment' - label = 'Attachments' - url_name = 'attachment' - template_name = 'attachments/attachments.html' + icon = "paperclip" + name = "attachment" + label = "Attachments" + url_name = "attachment" + template_name = "attachments/attachments.html" extra = 5 def get_formset(self, request): @@ -31,7 +31,7 @@ def get_formset(self, request): return modelformset_factory( Attachment, form=form, - fields=('file', 'description'), + fields=("file", "description"), extra=self.extra, can_delete=True, )(request.POST or None, request.FILES or None, queryset=qs) @@ -64,35 +64,30 @@ def formset_valid(self, formset): AttachmentItem.objects.refresh( self.object, [obj for obj in formset.new_objects if obj is not None], - formset.deleted_objects + formset.deleted_objects, ) - return HttpResponseRedirect('.') + return HttpResponseRedirect(".") def formset_invalid(self, formset): """ The method is executed only if formset is invalid. """ - return self.render_to_response( - self.get_context_data(formset=formset) - ) + return self.render_to_response(self.get_context_data(formset=formset)) class ServeAttachment(View): - def get(self, request, id, filename, *args, **kwargs): """ All attachments are serving by this view because we need full control (e.g., permissions, rename). """ # TODO: respect permissions - obj = get_object_or_404( - Attachment, - id=id, - original_filename=filename - ) - fd = open(obj.file.path, 'rb') + obj = get_object_or_404(Attachment, id=id, original_filename=filename) + fd = open(obj.file.path, "rb") response = FileResponse(fd, content_type=obj.mime_type) - response['Content-Disposition'] = 'attachment; filename="{}"'.format(obj.original_filename) # noqa + response["Content-Disposition"] = 'attachment; filename="{}"'.format( + obj.original_filename + ) # noqa http_modified = http_date(time.mktime(obj.modified.timetuple())) - response['Last-Modified'] = http_modified + response["Last-Modified"] = http_modified return response diff --git a/src/ralph/back_office/__init__.py b/src/ralph/back_office/__init__.py index 2e66514d7a..637dc6c4a4 100644 --- a/src/ralph/back_office/__init__.py +++ b/src/ralph/back_office/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.back_office.apps.BackOfficeConfig' +default_app_config = "ralph.back_office.apps.BackOfficeConfig" diff --git a/src/ralph/back_office/admin.py b/src/ralph/back_office/admin.py index 6719c5510a..25e7e9f747 100644 --- a/src/ralph/back_office/admin.py +++ b/src/ralph/back_office/admin.py @@ -7,11 +7,7 @@ from ralph.admin.decorators import register from ralph.admin.filters import LiquidatedStatusFilter, TagsListFilter -from ralph.admin.mixins import ( - BulkEditChangeListMixin, - RalphAdmin, - RalphTabularInline -) +from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphTabularInline from ralph.admin.sites import ralph_site from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.admin.views.multiadd import MulitiAddAdminMixin @@ -20,11 +16,7 @@ from ralph.assets.invoice_report import AssetInvoiceReportMixin from ralph.assets.models import ObjectModelType from ralph.attachments.admin import AttachmentsMixin -from ralph.back_office.models import ( - BackOfficeAsset, - OfficeInfrastructure, - Warehouse -) +from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse from ralph.data_importer import resources from ralph.lib.custom_fields.admin import CustomFieldValueAdminMixin from ralph.lib.mixins.forms import AssetFormMixin, PriceFormMixin @@ -35,40 +27,39 @@ class BackOfficeAssetSupport(RalphDetailViewAdmin): - icon = 'bookmark' - name = 'bo_asset_support' - label = _('Supports') - url_name = 'back_office_asset_support' + icon = "bookmark" + name = "bo_asset_support" + label = _("Supports") + url_name = "back_office_asset_support" class BackOfficeAssetSupportInline(RalphTabularInline): model = BaseObjectsSupport - raw_id_fields = ('support',) + raw_id_fields = ("support",) extra = 1 - verbose_name = _('Support') - ordering = ['-support__date_to'] + verbose_name = _("Support") + ordering = ["-support__date_to"] inlines = [BackOfficeAssetSupportInline] class BackOfficeAssetLicence(RalphDetailViewAdmin): - - icon = 'key' - name = 'bo_asset_licence' - label = _('Licence') - url_name = 'back_office_asset_licence' + icon = "key" + name = "bo_asset_licence" + label = _("Licence") + url_name = "back_office_asset_licence" class BackOfficeAssetLicenceInline(RalphTabularInline): model = BaseObjectLicence - raw_id_fields = ('licence',) + raw_id_fields = ("licence",) extra = 1 - verbose_name = _('Licence') + verbose_name = _("Licence") inlines = [BackOfficeAssetLicenceInline] class BackOfficeAssetOperation(OperationViewReadOnlyForExisiting): - name = 'bc_asset_operations' - url_name = 'back_office_asset_operations' + name = "bc_asset_operations" + url_name = "back_office_asset_operations" inlines = OperationViewReadOnlyForExisiting.admin_class.inlines @@ -77,16 +68,14 @@ class BackOfficeAssetAdminForm(PriceFormMixin, AssetFormMixin, RalphAdmin.form): """ Service_env is not required for BackOffice assets. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if ( - 'hostname' in self.fields and - settings.BACKOFFICE_HOSTNAME_FIELD_READONLY - ): - self.fields['hostname'].widget.attrs['readonly'] = True + if "hostname" in self.fields and settings.BACKOFFICE_HOSTNAME_FIELD_READONLY: + self.fields["hostname"].widget.attrs["readonly"] = True # backward compatibility - service_env_field = self.fields.get('service_env', None) + service_env_field = self.fields.get("service_env", None) if service_env_field: service_env_field.required = False @@ -99,13 +88,13 @@ class BackOfficeAssetAdmin( TransitionAdminMixin, AssetInvoiceReportMixin, CustomFieldValueAdminMixin, - RalphAdmin + RalphAdmin, ): - """Back Office Asset admin class.""" - add_form_template = 'backofficeasset/add_form.html' + + add_form_template = "backofficeasset/add_form.html" form = BackOfficeAssetAdminForm - actions = ['bulk_edit_action'] + actions = ["bulk_edit_action"] show_transition_history = True change_views = [ BackOfficeAssetLicence, @@ -116,93 +105,196 @@ class BackOfficeAssetAdmin( # BackOfficeAssetSoftware, ] list_display = [ - 'status', 'barcode', 'purchase_order', 'model', 'get_user', 'warehouse', - 'service_env', 'sn', 'hostname', 'invoice_date', 'invoice_no', - 'region', 'property_of', 'buyout_date_display' + "status", + "barcode", + "purchase_order", + "model", + "get_user", + "warehouse", + "service_env", + "sn", + "hostname", + "invoice_date", + "invoice_no", + "region", + "property_of", + "buyout_date_display", ] multiadd_summary_fields = list_display - search_fields = ['barcode', 'sn', 'hostname', 'invoice_no', 'order_no'] + search_fields = ["barcode", "sn", "hostname", "invoice_no", "order_no"] def get_search_results(self, request, queryset, search_term): - queryset, use_distinct = super().get_search_results(request, queryset, search_term) # noqa - if 'barcode' in request.GET: - barcode = request.GET.get('barcode').split(";") + queryset, use_distinct = super().get_search_results( + request, queryset, search_term + ) # noqa + if "barcode" in request.GET: + barcode = request.GET.get("barcode").split(";") queryset = self.model.objects.filter(barcode__in=barcode) return queryset, use_distinct list_filter = [ - 'barcode', 'status', 'imei', 'imei2', 'sn', 'model', 'purchase_order', - 'hostname', 'required_support', 'region', 'warehouse', 'task_url', - 'model__category', 'loan_end_date', 'niw', 'model__manufacturer', - 'model__manufacturer__manufacturer_kind', 'location', 'remarks', - 'user', 'owner', 'user__segment', 'user__company', 'user__department', - 'user__employee_id', 'property_of', 'invoice_no', 'invoice_date', - 'order_no', 'provider', 'budget_info', 'depreciation_rate', - 'depreciation_end_date', 'force_depreciation', - ('buyout_date', BuyoutDateFilter), LiquidatedStatusFilter, - TagsListFilter, 'service_env' + "barcode", + "status", + "imei", + "imei2", + "sn", + "model", + "purchase_order", + "hostname", + "required_support", + "region", + "warehouse", + "task_url", + "model__category", + "loan_end_date", + "niw", + "model__manufacturer", + "model__manufacturer__manufacturer_kind", + "location", + "remarks", + "user", + "owner", + "user__segment", + "user__company", + "user__department", + "user__employee_id", + "property_of", + "invoice_no", + "invoice_date", + "order_no", + "provider", + "budget_info", + "depreciation_rate", + "depreciation_end_date", + "force_depreciation", + ("buyout_date", BuyoutDateFilter), + LiquidatedStatusFilter, + TagsListFilter, + "service_env", ] - date_hierarchy = 'created' + date_hierarchy = "created" list_select_related = [ - 'model', 'user', 'warehouse', 'model__manufacturer', 'region', - 'model__category', 'property_of', 'service_env', - 'service_env__service', 'service_env__environment' + "model", + "user", + "warehouse", + "model__manufacturer", + "region", + "model__category", + "property_of", + "service_env", + "service_env__service", + "service_env__environment", ] raw_id_fields = [ - 'model', 'user', 'owner', 'region', 'warehouse', - 'property_of', 'budget_info', 'office_infrastructure', 'service_env' + "model", + "user", + "owner", + "region", + "warehouse", + "property_of", + "budget_info", + "office_infrastructure", + "service_env", ] resource_class = resources.BackOfficeAssetResource bulk_edit_list = [ - 'licences', 'status', 'barcode', 'imei', 'imei2', 'hostname', 'model', - 'purchase_order', 'user', 'owner', 'warehouse', 'sn', 'region', - 'property_of', 'remarks', 'invoice_date', 'invoice_no', 'provider', - 'task_url', 'service_env', 'depreciation_rate', 'price', 'order_no', - 'depreciation_end_date', 'tags', 'start_usage' + "licences", + "status", + "barcode", + "imei", + "imei2", + "hostname", + "model", + "purchase_order", + "user", + "owner", + "warehouse", + "sn", + "region", + "property_of", + "remarks", + "invoice_date", + "invoice_no", + "provider", + "task_url", + "service_env", + "depreciation_rate", + "price", + "order_no", + "depreciation_end_date", + "tags", + "start_usage", ] - bulk_edit_no_fillable = ['barcode', 'sn', 'imei', 'imei2', 'hostname'] - _invoice_report_name = 'invoice-back-office-asset' + bulk_edit_no_fillable = ["barcode", "sn", "imei", "imei2", "hostname"] + _invoice_report_name = "invoice-back-office-asset" _invoice_report_item_fields = ( - AssetInvoiceReportMixin._invoice_report_item_fields + ['owner'] + AssetInvoiceReportMixin._invoice_report_item_fields + ["owner"] ) _invoice_report_select_related = ( - AssetInvoiceReportMixin._invoice_report_select_related + ['owner'] + AssetInvoiceReportMixin._invoice_report_select_related + ["owner"] ) fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'hostname', 'model', 'barcode', 'sn', 'imei', 'imei2', 'niw', - 'status', 'last_status_change', 'warehouse', 'location', - 'region', 'loan_end_date', 'remarks', 'tags', 'property_of', - 'task_url', 'service_env', 'office_infrastructure' - ) - }), - (_('User Info'), { - 'fields': ( - 'user', 'owner' - ) - }), - (_('Financial Info'), { - 'fields': ( - 'order_no', 'purchase_order', 'invoice_date', 'invoice_no', - 'price', 'depreciation_rate', 'depreciation_end_date', - 'force_depreciation', 'provider', 'budget_info', 'start_usage' - ) - }), + ( + _("Basic info"), + { + "fields": ( + "hostname", + "model", + "barcode", + "sn", + "imei", + "imei2", + "niw", + "status", + "last_status_change", + "warehouse", + "location", + "region", + "loan_end_date", + "remarks", + "tags", + "property_of", + "task_url", + "service_env", + "office_infrastructure", + ) + }, + ), + (_("User Info"), {"fields": ("user", "owner")}), + ( + _("Financial Info"), + { + "fields": ( + "order_no", + "purchase_order", + "invoice_date", + "invoice_no", + "price", + "depreciation_rate", + "depreciation_end_date", + "force_depreciation", + "provider", + "budget_info", + "start_usage", + ) + }, + ), ) def licences(self, obj): - return '' - licences.short_description = 'licences' + return "" + + licences.short_description = "licences" def buyout_date_display(self, obj): if obj.model.category.show_buyout_date: return obj.buyout_date return None - buyout_date_display.short_description = _('buyout date') - buyout_date_display.admin_order_field = 'buyout_date' + + buyout_date_display.short_description = _("buyout date") + buyout_date_display.admin_order_field = "buyout_date" def get_changelist_form(self, request, **kwargs): """ @@ -218,13 +310,15 @@ class BackOfficeAssetBulkForm(Form): editing licence on asset form is impossible with regular Django-Admin features. This solves that. """ + licences = forms.ModelMultipleChoiceField( - queryset=Licence.objects.all(), label=_('licences'), + queryset=Licence.objects.all(), + label=_("licences"), required=False, widget=AutocompleteWidget( - field=apps.get_model( - 'licences.BaseObjectLicence' - )._meta.get_field('licence'), + field=apps.get_model("licences.BaseObjectLicence")._meta.get_field( + "licence" + ), admin_site=ralph_site, request=request, multi=True, @@ -232,24 +326,25 @@ class BackOfficeAssetBulkForm(Form): ) def __init__(self, *args, **kwargs): - initial = kwargs.get('initial', {}) - initial['licences'] = [ + initial = kwargs.get("initial", {}) + initial["licences"] = [ # TODO: permissions handling: now this field is only visible # to superusers - str(_id) for _id in - kwargs['instance'].licences.values_list( - 'licence__id', flat=True + str(_id) + for _id in kwargs["instance"].licences.values_list( + "licence__id", flat=True ) ] - kwargs['initial'] = initial + kwargs["initial"] = initial super().__init__(*args, **kwargs) def save_m2m(self): - form_licences = self.cleaned_data['licences'] + form_licences = self.cleaned_data["licences"] form_licences_ids = [licence.id for licence in form_licences] asset_licences_ids = self.instance.licences.values_list( - 'licence__id', flat=True) + "licence__id", flat=True + ) to_add = set(form_licences_ids) - set(asset_licences_ids) to_remove = set(asset_licences_ids) - set(form_licences_ids) @@ -257,7 +352,8 @@ def save_m2m(self): if licence.id not in to_add: continue BaseObjectLicence.objects.get_or_create( - base_object=self.instance, licence_id=licence.id, + base_object=self.instance, + licence_id=licence.id, ) self.instance.licences.filter(licence_id__in=to_remove).delete() return self.instance @@ -271,39 +367,35 @@ def save(self, commit=True): def get_multiadd_fields(self, obj=None): multi_add_fields = [ - {'field': 'sn', 'allow_duplicates': False}, - {'field': 'barcode', 'allow_duplicates': False}, + {"field": "sn", "allow_duplicates": False}, + {"field": "barcode", "allow_duplicates": False}, ] # Check only obj, because model is required field if obj and obj.model.category.imei_required: - multi_add_fields.append( - {'field': 'imei', 'allow_duplicates': False} - ) - multi_add_fields.append( - {'field': 'imei2', 'allow_duplicates': False} - ) + multi_add_fields.append({"field": "imei", "allow_duplicates": False}) + multi_add_fields.append({"field": "imei2", "allow_duplicates": False}) return multi_add_fields @mark_safe def get_user(self, obj): if not obj.user_id: - return '-' + return "-" return '{} {} ({})'.format( obj.user.get_absolute_url(), obj.user.first_name, obj.user.last_name, - obj.user.username + obj.user.username, ) - get_user.short_description = _('User') - get_user.admin_order_field = 'get_user' + + get_user.short_description = _("User") + get_user.admin_order_field = "get_user" @register(Warehouse) class WarehouseAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(OfficeInfrastructure) class OfficeInfrastructureAdmin(RalphAdmin): - search_fields = ['name'] + search_fields = ["name"] diff --git a/src/ralph/back_office/api.py b/src/ralph/back_office/api.py index 7e27299c97..ef75a51cea 100644 --- a/src/ralph/back_office/api.py +++ b/src/ralph/back_office/api.py @@ -4,11 +4,7 @@ from ralph.assets.api.serializers import AssetSerializer from ralph.assets.api.views import base_object_descendant_prefetch_related from ralph.back_office.admin import BackOfficeAssetAdmin -from ralph.back_office.models import ( - BackOfficeAsset, - OfficeInfrastructure, - Warehouse -) +from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse class WarehouseSerializer(RalphAPISerializer): @@ -53,23 +49,29 @@ class Meta(AssetSerializer.Meta): class BackOfficeAssetViewSet(RalphAPIViewSet): select_related = BackOfficeAssetAdmin.list_select_related + [ - 'service_env', 'service_env__service', 'service_env__environment', - 'user', 'owner', 'property_of', 'office_infrastructure', - 'budget_info', + "service_env", + "service_env__service", + "service_env__environment", + "user", + "owner", + "property_of", + "office_infrastructure", + "budget_info", ] prefetch_related = base_object_descendant_prefetch_related + [ - 'user__groups', 'user__user_permissions', - 'service_env__service__environments', - 'service_env__service__business_owners', - 'service_env__service__technical_owners', - 'tags', - 'content_type', + "user__groups", + "user__user_permissions", + "service_env__service__environments", + "service_env__service__business_owners", + "service_env__service__technical_owners", + "tags", + "content_type", ] queryset = BackOfficeAsset.objects.all() serializer_class = BackOfficeAssetSerializer -router.register(r'warehouses', WarehouseViewSet) -router.register(r'office-infrastructures', OfficeInfrastructureViewSet) -router.register(r'back-office-assets', BackOfficeAssetViewSet) +router.register(r"warehouses", WarehouseViewSet) +router.register(r"office-infrastructures", OfficeInfrastructureViewSet) +router.register(r"back-office-assets", BackOfficeAssetViewSet) urlpatterns = [] diff --git a/src/ralph/back_office/apps.py b/src/ralph/back_office/apps.py index 88cf128c0a..6719af1994 100644 --- a/src/ralph/back_office/apps.py +++ b/src/ralph/back_office/apps.py @@ -2,5 +2,5 @@ class BackOfficeConfig(RalphAppConfig): - name = 'ralph.back_office' - verbose_name = 'Back Office' + name = "ralph.back_office" + verbose_name = "Back Office" diff --git a/src/ralph/back_office/helpers.py b/src/ralph/back_office/helpers.py index c1f194dc8f..48323802bd 100644 --- a/src/ralph/back_office/helpers.py +++ b/src/ralph/back_office/helpers.py @@ -5,22 +5,22 @@ from ralph.back_office.models import BackOfficeAssetStatus from ralph.data_center.models import DataCenterAssetStatus -EmailContext = namedtuple('EmailContext', 'from_email subject body') +EmailContext = namedtuple("EmailContext", "from_email subject body") def get_email_context_for_transition(transition_name: str) -> EmailContext: """Default method used in action (send_attachments_to_user).""" default = { - 'from_email': settings.EMAIL_FROM, - 'subject': 'Documents for {}'.format(transition_name), - 'body': 'Please see documents provided in attachments for "{}".'.format(transition_name) # noqa + "from_email": settings.EMAIL_FROM, + "subject": "Documents for {}".format(transition_name), + "body": 'Please see documents provided in attachments for "{}".'.format( + transition_name + ), # noqa } return EmailContext(**default) -def _status_converter( - old_status_id, target_status_id, from_status_cls, to_status_cls -): +def _status_converter(old_status_id, target_status_id, from_status_cls, to_status_cls): """ Convert BackOfficeAsset (BO) status to DatacenterAsset (DC) status (or the other way round). @@ -55,7 +55,7 @@ def bo_asset_to_dc_asset_status_converter(old_status_id, target_status_id): old_status_id, target_status_id, from_status_cls=BackOfficeAssetStatus, - to_status_cls=DataCenterAssetStatus + to_status_cls=DataCenterAssetStatus, ) @@ -64,5 +64,5 @@ def dc_asset_to_bo_asset_status_converter(old_status_id, target_status_id): old_status_id, target_status_id, from_status_cls=DataCenterAssetStatus, - to_status_cls=BackOfficeAssetStatus + to_status_cls=BackOfficeAssetStatus, ) diff --git a/src/ralph/back_office/migrations/0001_initial.py b/src/ralph/back_office/migrations/0001_initial.py index 45e890e75d..ce81bf0062 100644 --- a/src/ralph/back_office/migrations/0001_initial.py +++ b/src/ralph/back_office/migrations/0001_initial.py @@ -9,78 +9,180 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0001_initial'), + ("assets", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('accounts', '0001_initial'), + ("accounts", "0001_initial"), ] operations = [ migrations.CreateModel( - name='BackOfficeAsset', + name="BackOfficeAsset", fields=[ - ('asset_ptr', models.OneToOneField(primary_key=True, to='assets.Asset', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), - ('location', models.CharField(blank=True, null=True, max_length=128)), - ('purchase_order', models.CharField(blank=True, null=True, max_length=50)), - ('loan_end_date', models.DateField(verbose_name='Loan end date', blank=True, default=None, null=True)), - ('status', ralph.lib.transitions.fields.TransitionField(choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved')], default=1)), - ('imei', ralph.lib.mixins.fields.NullableCharField(blank=True, null=True, unique=True, max_length=18)), + ( + "asset_ptr", + models.OneToOneField( + primary_key=True, + to="assets.Asset", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("location", models.CharField(blank=True, null=True, max_length=128)), + ( + "purchase_order", + models.CharField(blank=True, null=True, max_length=50), + ), + ( + "loan_end_date", + models.DateField( + verbose_name="Loan end date", + blank=True, + default=None, + null=True, + ), + ), + ( + "status", + ralph.lib.transitions.fields.TransitionField( + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + ], + default=1, + ), + ), + ( + "imei", + ralph.lib.mixins.fields.NullableCharField( + blank=True, null=True, unique=True, max_length=18 + ), + ), ], options={ - 'verbose_name': 'Back Office Asset', - 'verbose_name_plural': 'Back Office Assets', + "verbose_name": "Back Office Asset", + "verbose_name_plural": "Back Office Assets", }, - bases=('assets.asset', models.Model), + bases=("assets.asset", models.Model), ), migrations.CreateModel( - name='OfficeInfrastructure', + name="OfficeInfrastructure", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'verbose_name': 'Office Infrastructure', - 'verbose_name_plural': 'Office Infrastructures', + "verbose_name": "Office Infrastructure", + "verbose_name_plural": "Office Infrastructures", }, ), migrations.CreateModel( - name='Warehouse', + name="Warehouse", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.AddField( - model_name='backofficeasset', - name='office_infrastructure', - field=models.ForeignKey(to='back_office.OfficeInfrastructure', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="backofficeasset", + name="office_infrastructure", + field=models.ForeignKey( + to="back_office.OfficeInfrastructure", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='backofficeasset', - name='owner', - field=models.ForeignKey(to=settings.AUTH_USER_MODEL, blank=True, null=True, related_name='assets_as_owner', on_delete=django.db.models.deletion.CASCADE), + model_name="backofficeasset", + name="owner", + field=models.ForeignKey( + to=settings.AUTH_USER_MODEL, + blank=True, + null=True, + related_name="assets_as_owner", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='backofficeasset', - name='region', - field=models.ForeignKey(to='accounts.Region', on_delete=django.db.models.deletion.CASCADE), + model_name="backofficeasset", + name="region", + field=models.ForeignKey( + to="accounts.Region", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AddField( - model_name='backofficeasset', - name='user', - field=models.ForeignKey(to=settings.AUTH_USER_MODEL, blank=True, null=True, related_name='assets_as_user', on_delete=django.db.models.deletion.CASCADE), + model_name="backofficeasset", + name="user", + field=models.ForeignKey( + to=settings.AUTH_USER_MODEL, + blank=True, + null=True, + related_name="assets_as_user", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='backofficeasset', - name='warehouse', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='back_office.Warehouse'), + model_name="backofficeasset", + name="warehouse", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="back_office.Warehouse" + ), ), ] diff --git a/src/ralph/back_office/migrations/0002_auto_20151125_1354.py b/src/ralph/back_office/migrations/0002_auto_20151125_1354.py index 19ec45a3f0..7f2b31ef92 100644 --- a/src/ralph/back_office/migrations/0002_auto_20151125_1354.py +++ b/src/ralph/back_office/migrations/0002_auto_20151125_1354.py @@ -5,30 +5,29 @@ class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0001_initial'), + ("back_office", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='officeinfrastructure', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="officeinfrastructure", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='officeinfrastructure', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="officeinfrastructure", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='warehouse', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="warehouse", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='warehouse', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="warehouse", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), ] diff --git a/src/ralph/back_office/migrations/0003_auto_20151204_0758.py b/src/ralph/back_office/migrations/0003_auto_20151204_0758.py index 6414f18c24..ea1a61fdaf 100644 --- a/src/ralph/back_office/migrations/0003_auto_20151204_0758.py +++ b/src/ralph/back_office/migrations/0003_auto_20151204_0758.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0002_auto_20151125_1354'), + ("back_office", "0002_auto_20151125_1354"), ] operations = [ migrations.AlterModelOptions( - name='warehouse', - options={'ordering': ['name']}, + name="warehouse", + options={"ordering": ["name"]}, ), ] diff --git a/src/ralph/back_office/migrations/0004_warehouse_stocktaking_enabled.py b/src/ralph/back_office/migrations/0004_warehouse_stocktaking_enabled.py index 3890b83375..a6ff3a6260 100644 --- a/src/ralph/back_office/migrations/0004_warehouse_stocktaking_enabled.py +++ b/src/ralph/back_office/migrations/0004_warehouse_stocktaking_enabled.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0003_auto_20151204_0758'), + ("back_office", "0003_auto_20151204_0758"), ] operations = [ migrations.AddField( - model_name='warehouse', - name='stocktaking_enabled', + model_name="warehouse", + name="stocktaking_enabled", field=models.BooleanField(default=False), ), ] diff --git a/src/ralph/back_office/migrations/0005_warehouse_stocktaking_tag_suffix.py b/src/ralph/back_office/migrations/0005_warehouse_stocktaking_tag_suffix.py index e4fe1edfdf..9f8687519e 100644 --- a/src/ralph/back_office/migrations/0005_warehouse_stocktaking_tag_suffix.py +++ b/src/ralph/back_office/migrations/0005_warehouse_stocktaking_tag_suffix.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0004_warehouse_stocktaking_enabled'), + ("back_office", "0004_warehouse_stocktaking_enabled"), ] operations = [ migrations.AddField( - model_name='warehouse', - name='stocktaking_tag_suffix', - field=models.CharField(max_length=8, default=''), + model_name="warehouse", + name="stocktaking_tag_suffix", + field=models.CharField(max_length=8, default=""), ), ] diff --git a/src/ralph/back_office/migrations/0006_auto_20160902_1238.py b/src/ralph/back_office/migrations/0006_auto_20160902_1238.py index a40c5e1d0e..169859cd5e 100644 --- a/src/ralph/back_office/migrations/0006_auto_20160902_1238.py +++ b/src/ralph/back_office/migrations/0006_auto_20160902_1238.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0005_warehouse_stocktaking_tag_suffix'), + ("back_office", "0005_warehouse_stocktaking_tag_suffix"), ] operations = [ migrations.AlterField( - model_name='warehouse', - name='stocktaking_tag_suffix', - field=models.CharField(blank=True, default='', max_length=8), + model_name="warehouse", + name="stocktaking_tag_suffix", + field=models.CharField(blank=True, default="", max_length=8), ), ] diff --git a/src/ralph/back_office/migrations/0007_auto_20180105_0910.py b/src/ralph/back_office/migrations/0007_auto_20180105_0910.py index 0a64643e2c..28c7053084 100644 --- a/src/ralph/back_office/migrations/0007_auto_20180105_0910.py +++ b/src/ralph/back_office/migrations/0007_auto_20180105_0910.py @@ -1,20 +1,35 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0006_auto_20160902_1238'), + ("back_office", "0006_auto_20160902_1238"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale')], default=1), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + ], + default=1, + ), ), ] diff --git a/src/ralph/back_office/migrations/0008_auto_20180801_1157.py b/src/ralph/back_office/migrations/0008_auto_20180801_1157.py index 751d49f39d..354156703b 100644 --- a/src/ralph/back_office/migrations/0008_auto_20180801_1157.py +++ b/src/ralph/back_office/migrations/0008_auto_20180801_1157.py @@ -1,20 +1,36 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0007_auto_20180105_0910'), + ("back_office", "0007_auto_20180105_0910"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0009_auto_20181016_1252.py b/src/ralph/back_office/migrations/0009_auto_20181016_1252.py index 2bcc889dae..dc2f4adc9e 100644 --- a/src/ralph/back_office/migrations/0009_auto_20181016_1252.py +++ b/src/ralph/back_office/migrations/0009_auto_20181016_1252.py @@ -1,20 +1,37 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0008_auto_20180801_1157'), + ("back_office", "0008_auto_20180801_1157"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py b/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py index 8222613a0e..ca7bb23ab6 100644 --- a/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py +++ b/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py @@ -1,20 +1,21 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0009_auto_20181016_1252'), + ("back_office", "0009_auto_20181016_1252"), ] operations = [ migrations.AddField( - model_name='backofficeasset', - name='imei2', - field=ralph.lib.mixins.fields.NullableCharField(max_length=18, unique=True, blank=True, null=True), + model_name="backofficeasset", + name="imei2", + field=ralph.lib.mixins.fields.NullableCharField( + max_length=18, unique=True, blank=True, null=True + ), ), ] diff --git a/src/ralph/back_office/migrations/0011_auto_20190517_1115.py b/src/ralph/back_office/migrations/0011_auto_20190517_1115.py index a4824b57e0..a18bbc45cd 100644 --- a/src/ralph/back_office/migrations/0011_auto_20190517_1115.py +++ b/src/ralph/back_office/migrations/0011_auto_20190517_1115.py @@ -1,25 +1,28 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0010_backofficeasset_imei2'), + ("back_office", "0010_backofficeasset_imei2"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='imei', - field=ralph.lib.mixins.fields.NullableCharField(verbose_name='IMEI', max_length=18, unique=True, blank=True, null=True), + model_name="backofficeasset", + name="imei", + field=ralph.lib.mixins.fields.NullableCharField( + verbose_name="IMEI", max_length=18, unique=True, blank=True, null=True + ), ), migrations.AlterField( - model_name='backofficeasset', - name='imei2', - field=ralph.lib.mixins.fields.NullableCharField(verbose_name='IMEI 2', max_length=18, unique=True, blank=True, null=True), + model_name="backofficeasset", + name="imei2", + field=ralph.lib.mixins.fields.NullableCharField( + verbose_name="IMEI 2", max_length=18, unique=True, blank=True, null=True + ), ), ] diff --git a/src/ralph/back_office/migrations/0012_auto_20210318_1230.py b/src/ralph/back_office/migrations/0012_auto_20210318_1230.py index 2e2ea9eb5e..726fbce358 100644 --- a/src/ralph/back_office/migrations/0012_auto_20210318_1230.py +++ b/src/ralph/back_office/migrations/0012_auto_20210318_1230.py @@ -1,20 +1,38 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0011_auto_20190517_1115'), + ("back_office", "0011_auto_20190517_1115"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0013_auto_20220421_1202.py b/src/ralph/back_office/migrations/0013_auto_20220421_1202.py index 6ccd02685a..01ee05927d 100644 --- a/src/ralph/back_office/migrations/0013_auto_20220421_1202.py +++ b/src/ralph/back_office/migrations/0013_auto_20220421_1202.py @@ -1,20 +1,39 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0012_auto_20210318_1230'), + ("back_office", "0012_auto_20210318_1230"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0014_auto_20221108_1007.py b/src/ralph/back_office/migrations/0014_auto_20221108_1007.py index 4cade11488..98b027eab8 100644 --- a/src/ralph/back_office/migrations/0014_auto_20221108_1007.py +++ b/src/ralph/back_office/migrations/0014_auto_20221108_1007.py @@ -1,20 +1,40 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0013_auto_20220421_1202'), + ("back_office", "0013_auto_20220421_1202"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'buyout')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "buyout"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0015_auto_20221207_1445.py b/src/ralph/back_office/migrations/0015_auto_20221207_1445.py index a090f4da20..c823f0feea 100644 --- a/src/ralph/back_office/migrations/0015_auto_20221207_1445.py +++ b/src/ralph/back_office/migrations/0015_auto_20221207_1445.py @@ -1,20 +1,42 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0014_auto_20221108_1007'), + ("back_office", "0014_auto_20221108_1007"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'buyout'), (18, 'in use team'), (19, 'in use test')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "buyout"), + (18, "in use team"), + (19, "in use test"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0016_auto_20221220_1210.py b/src/ralph/back_office/migrations/0016_auto_20221220_1210.py index aefce26d19..a9e1be6a4f 100644 --- a/src/ralph/back_office/migrations/0016_auto_20221220_1210.py +++ b/src/ralph/back_office/migrations/0016_auto_20221220_1210.py @@ -1,20 +1,42 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0015_auto_20221207_1445'), + ("back_office", "0015_auto_20221207_1445"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'to buyout'), (18, 'in use team'), (19, 'in use test')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "to buyout"), + (18, "in use team"), + (19, "in use test"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0017_auto_20230112_0949.py b/src/ralph/back_office/migrations/0017_auto_20230112_0949.py index e4f0049ff1..fd874877d2 100644 --- a/src/ralph/back_office/migrations/0017_auto_20230112_0949.py +++ b/src/ralph/back_office/migrations/0017_auto_20230112_0949.py @@ -1,20 +1,44 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0016_auto_20221220_1210'), + ("back_office", "0016_auto_20221220_1210"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'to buyout'), (18, 'in use team'), (19, 'in use test'), (20, 'in_progress team'), (21, 'in progress test')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "to buyout"), + (18, "in use team"), + (19, "in use test"), + (20, "in_progress team"), + (21, "in progress test"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0018_auto_20230206_1020.py b/src/ralph/back_office/migrations/0018_auto_20230206_1020.py index 7505761477..577dc3d571 100644 --- a/src/ralph/back_office/migrations/0018_auto_20230206_1020.py +++ b/src/ralph/back_office/migrations/0018_auto_20230206_1020.py @@ -1,20 +1,45 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0017_auto_20230112_0949'), + ("back_office", "0017_auto_20230112_0949"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'to buyout'), (18, 'in use team'), (19, 'in use test'), (20, 'in progress team'), (21, 'in progress test'), (22, 'quarantine')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "to buyout"), + (18, "in use team"), + (19, "in use test"), + (20, "in progress team"), + (21, "in progress test"), + (22, "quarantine"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0019_backofficeasset_last_status_change.py b/src/ralph/back_office/migrations/0019_backofficeasset_last_status_change.py index 3892622619..2232d3f120 100644 --- a/src/ralph/back_office/migrations/0019_backofficeasset_last_status_change.py +++ b/src/ralph/back_office/migrations/0019_backofficeasset_last_status_change.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0018_auto_20230206_1020'), + ("back_office", "0018_auto_20230206_1020"), ] operations = [ migrations.AddField( - model_name='backofficeasset', - name='last_status_change', - field=models.DateField(verbose_name='Last status change', blank=True, null=True, default=None), + model_name="backofficeasset", + name="last_status_change", + field=models.DateField( + verbose_name="Last status change", blank=True, null=True, default=None + ), ), ] diff --git a/src/ralph/back_office/migrations/0020_auto_20230419_1223.py b/src/ralph/back_office/migrations/0020_auto_20230419_1223.py index 81c22b225a..3a1e2fa629 100644 --- a/src/ralph/back_office/migrations/0020_auto_20230419_1223.py +++ b/src/ralph/back_office/migrations/0020_auto_20230419_1223.py @@ -2,27 +2,28 @@ from __future__ import unicode_literals import django -from django.db import migrations, models +from django.db import migrations import datetime def forwards_func(apps, schema_editor): - BackOfficeAsset = apps.get_model('back_office', 'BackOfficeAsset') + BackOfficeAsset = apps.get_model("back_office", "BackOfficeAsset") today = datetime.date.today() - BackOfficeAsset.objects.filter(last_status_change__isnull=True).update(last_status_change=today) + BackOfficeAsset.objects.filter(last_status_change__isnull=True).update( + last_status_change=today + ) class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0019_backofficeasset_last_status_change'), + ("back_office", "0019_backofficeasset_last_status_change"), ] operations = [ migrations.AlterModelManagers( - name='backofficeasset', + name="backofficeasset", managers=[ - ('objects', django.db.models.manager.Manager()), + ("objects", django.db.models.manager.Manager()), ], ), migrations.RunPython(forwards_func), diff --git a/src/ralph/back_office/migrations/0021_auto_20230511_1202.py b/src/ralph/back_office/migrations/0021_auto_20230511_1202.py index 507bc37b54..d1642afdee 100644 --- a/src/ralph/back_office/migrations/0021_auto_20230511_1202.py +++ b/src/ralph/back_office/migrations/0021_auto_20230511_1202.py @@ -1,20 +1,46 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0020_auto_20230419_1223'), + ("back_office", "0020_auto_20230419_1223"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'to buyout'), (18, 'in use team'), (19, 'in use test'), (20, 'in progress team'), (21, 'in progress test'), (22, 'quarantine'), (23, 'refurbished')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "to buyout"), + (18, "in use team"), + (19, "in use test"), + (20, "in progress team"), + (21, "in progress test"), + (22, "quarantine"), + (23, "refurbished"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0022_auto_20230616_1235.py b/src/ralph/back_office/migrations/0022_auto_20230616_1235.py index 0177497ece..de2ae05960 100644 --- a/src/ralph/back_office/migrations/0022_auto_20230616_1235.py +++ b/src/ralph/back_office/migrations/0022_auto_20230616_1235.py @@ -1,20 +1,47 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0021_auto_20230511_1202'), + ("back_office", "0021_auto_20230511_1202"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'to buyout'), (18, 'in use team'), (19, 'in use test'), (20, 'in progress team'), (21, 'in progress test'), (22, 'quarantine'), (23, 'refurbished'), (24, 'reserved to order')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "to buyout"), + (18, "in use team"), + (19, "in use test"), + (20, "in progress team"), + (21, "in progress test"), + (22, "quarantine"), + (23, "refurbished"), + (24, "reserved to order"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0023_auto_20240223_1018.py b/src/ralph/back_office/migrations/0023_auto_20240223_1018.py index 4523db41a6..a10359a959 100644 --- a/src/ralph/back_office/migrations/0023_auto_20240223_1018.py +++ b/src/ralph/back_office/migrations/0023_auto_20240223_1018.py @@ -1,20 +1,48 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0022_auto_20230616_1235'), + ("back_office", "0022_auto_20230616_1235"), ] operations = [ migrations.AlterField( - model_name='backofficeasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'loan'), (6, 'damaged'), (7, 'liquidated'), (8, 'in service'), (9, 'installed'), (10, 'free'), (11, 'reserved'), (12, 'sale'), (13, 'loan in progress'), (14, 'return in progress'), (15, 'to find'), (16, 'sent'), (17, 'to buyout'), (18, 'in use team'), (19, 'in use test'), (20, 'in progress team'), (21, 'in progress test'), (22, 'quarantine'), (23, 'refurbished'), (24, 'reserved to order'), (25, 'replacement')]), + model_name="backofficeasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "loan"), + (6, "damaged"), + (7, "liquidated"), + (8, "in service"), + (9, "installed"), + (10, "free"), + (11, "reserved"), + (12, "sale"), + (13, "loan in progress"), + (14, "return in progress"), + (15, "to find"), + (16, "sent"), + (17, "to buyout"), + (18, "in use team"), + (19, "in use test"), + (20, "in progress team"), + (21, "in progress test"), + (22, "quarantine"), + (23, "refurbished"), + (24, "reserved to order"), + (25, "replacement"), + ], + ), ), ] diff --git a/src/ralph/back_office/migrations/0024_auto_20240621_1217.py b/src/ralph/back_office/migrations/0024_auto_20240621_1217.py index 7c01d89821..599a167e52 100644 --- a/src/ralph/back_office/migrations/0024_auto_20240621_1217.py +++ b/src/ralph/back_office/migrations/0024_auto_20240621_1217.py @@ -5,16 +5,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0023_auto_20240223_1018'), + ("back_office", "0023_auto_20240223_1018"), ] operations = [ migrations.AlterModelManagers( - name='backofficeasset', + name="backofficeasset", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/back_office/models.py b/src/ralph/back_office/models.py index 5320a238c9..2b2faee417 100644 --- a/src/ralph/back_office/models.py +++ b/src/ralph/back_office/models.py @@ -20,17 +20,13 @@ Asset, AssetLastHostname, AssetModel, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.utils import move_parents_models from ralph.attachments.utils import send_transition_attachments_to_user from ralph.lib.hooks import get_hook from ralph.lib.mixins.fields import NullableCharField -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin from ralph.lib.transitions.conf import get_report_name_for_transition_id from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.fields import TransitionField @@ -39,28 +35,19 @@ from ralph.reports.helpers import generate_report from ralph.reports.models import ReportLanguage -IMEI_UNTIL_2003 = re.compile(r'^\d{6} *\d{2} *\d{6} *\d$') -IMEI_SINCE_2003 = re.compile(r'^\d{8} *\d{6} *\d$') -ASSET_HOSTNAME_TEMPLATE = getattr(settings, 'ASSET_HOSTNAME_TEMPLATE', None) +IMEI_UNTIL_2003 = re.compile(r"^\d{6} *\d{2} *\d{6} *\d$") +IMEI_SINCE_2003 = re.compile(r"^\d{8} *\d{6} *\d$") +ASSET_HOSTNAME_TEMPLATE = getattr(settings, "ASSET_HOSTNAME_TEMPLATE", None) if not ASSET_HOSTNAME_TEMPLATE: raise ImproperlyConfigured('"ASSET_HOSTNAME_TEMPLATE" must be specified.') logger = logging.getLogger(__name__) -class Warehouse( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model -): +class Warehouse(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): _allow_in_dashboard = True stocktaking_enabled = models.BooleanField(default=False) - stocktaking_tag_suffix = models.CharField( - max_length=8, - default='', - blank=True - ) + stocktaking_tag_suffix = models.CharField(max_length=8, default="", blank=True) class BackOfficeAssetStatus(Choices): @@ -94,15 +81,11 @@ class BackOfficeAssetStatus(Choices): class OfficeInfrastructure( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model + AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model ): - class Meta: - verbose_name = _('Office Infrastructure') - verbose_name_plural = _('Office Infrastructures') + verbose_name = _("Office Infrastructure") + verbose_name_plural = _("Office Infrastructures") def _is_field_in_transition_actions(actions, field_name): @@ -110,7 +93,7 @@ def _is_field_in_transition_actions(actions, field_name): Returns True if there is field with given name in one of actions. """ for action in actions: - if field_name in getattr(action, 'form_fields', {}): + if field_name in getattr(action, "form_fields", {}): return True return False @@ -127,23 +110,23 @@ def get_user_iso3_country_name(user): def _check_assets_owner(instances, **kwargs): errors = {} - requester = kwargs.get('requester', None) + requester = kwargs.get("requester", None) if not requester: - return {'__all__': _('requester must be specified')} + return {"__all__": _("requester must be specified")} for instance in instances: if requester and instance.owner != requester: - errors[instance] = _('requester is not an owner of the asset') + errors[instance] = _("requester is not an owner of the asset") return errors def _check_assets_user(instances, **kwargs): errors = {} - requester = kwargs.get('requester', None) + requester = kwargs.get("requester", None) if not requester: - return {'__all__': _('requester must be specified')} + return {"__all__": _("requester must be specified")} for instance in instances: if requester and instance.user != requester: - errors[instance] = _('requester is not an user of the asset') + errors[instance] = _("requester is not an user of the asset") return errors @@ -151,12 +134,12 @@ def _check_user_assigned(instances, **kwargs): errors = {} for instance in instances: if not instance.user: - errors[instance] = _('user not assigned') + errors[instance] = _("user not assigned") return errors -def autocomplete_user(actions, objects, field_name='user'): - """ Returns default value for user transition field. +def autocomplete_user(actions, objects, field_name="user"): + """Returns default value for user transition field. When multiple assets are selected, default user/owner is returned only if all assets have the same user assigned. Otherwise None will be returned. @@ -182,43 +165,47 @@ class BackOfficeAsset(Regionalizable, Asset): warehouse = models.ForeignKey(Warehouse, on_delete=models.PROTECT) owner = models.ForeignKey( - settings.AUTH_USER_MODEL, null=True, blank=True, - related_name='assets_as_owner', on_delete=models.CASCADE + settings.AUTH_USER_MODEL, + null=True, + blank=True, + related_name="assets_as_owner", + on_delete=models.CASCADE, ) user = models.ForeignKey( - settings.AUTH_USER_MODEL, null=True, blank=True, - related_name='assets_as_user', on_delete=models.CASCADE + settings.AUTH_USER_MODEL, + null=True, + blank=True, + related_name="assets_as_user", + on_delete=models.CASCADE, ) location = models.CharField(max_length=128, null=True, blank=True) purchase_order = models.CharField(max_length=50, null=True, blank=True) loan_end_date = models.DateField( - null=True, blank=True, default=None, verbose_name=_('Loan end date'), + null=True, + blank=True, + default=None, + verbose_name=_("Loan end date"), ) status = TransitionField( default=BackOfficeAssetStatus.new.id, choices=BackOfficeAssetStatus(), ) imei = NullableCharField( - max_length=18, null=True, blank=True, unique=True, - verbose_name=_('IMEI') + max_length=18, null=True, blank=True, unique=True, verbose_name=_("IMEI") ) imei2 = NullableCharField( - max_length=18, null=True, blank=True, unique=True, - verbose_name=_('IMEI 2') + max_length=18, null=True, blank=True, unique=True, verbose_name=_("IMEI 2") ) office_infrastructure = models.ForeignKey( OfficeInfrastructure, null=True, blank=True, on_delete=models.CASCADE ) last_status_change = models.DateField( - null=True, - blank=True, - default=None, - verbose_name=_('Last status change') + null=True, blank=True, default=None, verbose_name=_("Last status change") ) class Meta: - verbose_name = _('Back Office Asset') - verbose_name_plural = _('Back Office Assets') + verbose_name = _("Back Office Asset") + verbose_name_plural = _("Back Office Assets") @property def country_code(self): @@ -226,12 +213,12 @@ def country_code(self): return iso2_to_iso3(iso2) def __str__(self): - return '{} (BC: {} / SN: {})'.format( - self.hostname or '-', self.barcode or '-', self.sn or '-' + return "{} (BC: {} / SN: {})".format( + self.hostname or "-", self.barcode or "-", self.sn or "-" ) def __repr__(self): - return ''.format(self.id) + return "".format(self.id) def validate_imei(self, imei): return IMEI_SINCE_2003.match(imei) or IMEI_UNTIL_2003.match(imei) @@ -239,21 +226,22 @@ def validate_imei(self, imei): def clean(self): super().clean() if self.imei and not self.validate_imei(self.imei): - raise ValidationError({ - 'imei': _('%(imei)s is not IMEI format') % {'imei': self.imei} - }) + raise ValidationError( + {"imei": _("%(imei)s is not IMEI format") % {"imei": self.imei}} + ) if self.imei2 and not self.validate_imei(self.imei2): - raise ValidationError({ - 'imei2': _('%(imei)s is not IMEI format') % {'imei': self.imei2} # noqa - }) + raise ValidationError( + { + "imei2": _("%(imei)s is not IMEI format") % {"imei": self.imei2} # noqa + } + ) def is_liquidated(self, date=None): date = date or datetime.date.today() # check if asset has status 'liquidated' and if yes, check if it has # this status on given date - if ( - self.status == BackOfficeAssetStatus.liquidated and - self._liquidated_at(date) + if self.status == BackOfficeAssetStatus.liquidated and self._liquidated_at( + date ): return True return False @@ -265,16 +253,18 @@ def render_template(template): return template.render(context) logger.info( - 'Generating new hostname for %s using %s old hostname %s', - self, template_vars, self.hostname + "Generating new hostname for %s using %s old hostname %s", + self, + template_vars, + self.hostname, ) prefix = render_template( - ASSET_HOSTNAME_TEMPLATE.get('prefix', ''), + ASSET_HOSTNAME_TEMPLATE.get("prefix", ""), ) postfix = render_template( - ASSET_HOSTNAME_TEMPLATE.get('postfix', ''), + ASSET_HOSTNAME_TEMPLATE.get("postfix", ""), ) - counter_length = ASSET_HOSTNAME_TEMPLATE.get('counter_length', 5) + counter_length = ASSET_HOSTNAME_TEMPLATE.get("counter_length", 5) last_hostname = AssetLastHostname.increment_hostname(prefix, postfix) self.hostname = last_hostname.formatted_hostname(fill=counter_length) if commit: @@ -284,117 +274,107 @@ def render_template(template): def _try_assign_hostname(self, commit=False, country=None, force=False): if self.model.category and self.model.category.code: template_vars = { - 'code': self.model.category.code, - 'country_code': country or self.country_code, + "code": self.model.category.code, + "country_code": country or self.country_code, } - if ( - force or - not self.hostname or - self.country_code not in self.hostname - ): + if force or not self.hostname or self.country_code not in self.hostname: self.generate_hostname(commit, template_vars) @classmethod def get_autocomplete_queryset(cls): - return cls._default_manager.exclude( - status=BackOfficeAssetStatus.liquidated.id - ) + return cls._default_manager.exclude(status=BackOfficeAssetStatus.liquidated.id) @classmethod @transition_action( form_fields={ - 'user': { - 'field': forms.CharField(label=_('User')), - 'autocomplete_field': 'user', - 'default_value': partial(autocomplete_user, field_name='user') + "user": { + "field": forms.CharField(label=_("User")), + "autocomplete_field": "user", + "default_value": partial(autocomplete_user, field_name="user"), } }, - run_after=['unassign_user'] + run_after=["unassign_user"], ) def assign_user(cls, instances, **kwargs): - user = get_user_model().objects.get(pk=int(kwargs['user'])) + user = get_user_model().objects.get(pk=int(kwargs["user"])) for instance in instances: instance.user = user @classmethod @transition_action( form_fields={ - 'owner': { - 'field': forms.CharField(label=_('Owner')), - 'autocomplete_field': 'owner', - 'default_value': partial(autocomplete_user, field_name='owner') + "owner": { + "field": forms.CharField(label=_("Owner")), + "autocomplete_field": "owner", + "default_value": partial(autocomplete_user, field_name="owner"), } }, help_text=_( - 'During this transition owner will be assigned as well as new ' - 'hostname might be generated for asset (only for particular model ' - 'categories and only if owner\'s country has changed)' + "During this transition owner will be assigned as well as new " + "hostname might be generated for asset (only for particular model " + "categories and only if owner's country has changed)" ), - run_after=['unassign_owner'] + run_after=["unassign_owner"], ) def assign_owner(cls, instances, **kwargs): - owner = get_user_model().objects.get(pk=int(kwargs['owner'])) + owner = get_user_model().objects.get(pk=int(kwargs["owner"])) for instance in instances: instance.owner = owner @classmethod @transition_action( form_fields={ - 'licences': { - 'field': forms.ModelMultipleChoiceField( - queryset=Licence.objects.all(), label=_('Licence'), + "licences": { + "field": forms.ModelMultipleChoiceField( + queryset=Licence.objects.all(), + label=_("Licence"), required=False, ), - 'autocomplete_field': 'licence', - 'autocomplete_model': 'licences.BaseObjectLicence', - 'widget_options': {'multi': True}, + "autocomplete_field": "licence", + "autocomplete_model": "licences.BaseObjectLicence", + "widget_options": {"multi": True}, } }, - run_after=['unassign_licences'] + run_after=["unassign_licences"], ) def assign_licence(cls, instances, **kwargs): for instance in instances: - for obj in kwargs['licences']: + for obj in kwargs["licences"]: BaseObjectLicence.objects.get_or_create( - base_object=instance, licence_id=obj.id, + base_object=instance, + licence_id=obj.id, ) @classmethod - @transition_action( - run_after=['loan_report', 'return_report'] - ) + @transition_action(run_after=["loan_report", "return_report"]) def unassign_owner(cls, instances, **kwargs): for instance in instances: - kwargs['history_kwargs'][instance.pk][ - 'affected_owner' - ] = str(instance.owner) + kwargs["history_kwargs"][instance.pk]["affected_owner"] = str( + instance.owner + ) instance.owner = None @classmethod - @transition_action( - run_after=['loan_report', 'return_report'] - ) + @transition_action(run_after=["loan_report", "return_report"]) def unassign_user(cls, instances, **kwargs): for instance in instances: - kwargs['history_kwargs'][instance.pk][ - 'affected_user' - ] = str(instance.user) + kwargs["history_kwargs"][instance.pk]["affected_user"] = str(instance.user) instance.user = None @classmethod @transition_action( form_fields={ - 'loan_end_date': { - 'field': forms.DateField( - label=_('Loan end date'), - widget=forms.TextInput(attrs={'class': 'datepicker'}) + "loan_end_date": { + "field": forms.DateField( + label=_("Loan end date"), + widget=forms.TextInput(attrs={"class": "datepicker"}), ) } }, ) def assign_loan_end_date(cls, instances, **kwargs): for instance in instances: - instance.loan_end_date = kwargs['loan_end_date'] + instance.loan_end_date = kwargs["loan_end_date"] @classmethod @transition_action() @@ -405,29 +385,29 @@ def unassign_loan_end_date(cls, instances, **kwargs): @classmethod @transition_action( form_fields={ - 'warehouse': { - 'field': forms.CharField(label=_('Warehouse')), - 'autocomplete_field': 'warehouse' + "warehouse": { + "field": forms.CharField(label=_("Warehouse")), + "autocomplete_field": "warehouse", } } ) def assign_warehouse(cls, instances, **kwargs): - warehouse = Warehouse.objects.get(pk=int(kwargs['warehouse'])) + warehouse = Warehouse.objects.get(pk=int(kwargs["warehouse"])) for instance in instances: instance.warehouse = warehouse @classmethod @transition_action( form_fields={ - 'office_infrastructure': { - 'field': forms.CharField(label=_('Office infrastructure')), - 'autocomplete_field': 'office_infrastructure' + "office_infrastructure": { + "field": forms.CharField(label=_("Office infrastructure")), + "autocomplete_field": "office_infrastructure", } }, ) def assign_office_infrastructure(cls, instances, **kwargs): office_inf = OfficeInfrastructure.objects.get( - pk=int(kwargs['office_infrastructure']) + pk=int(kwargs["office_infrastructure"]) ) for instance in instances: instance.office_infrastructure = office_inf @@ -435,28 +415,26 @@ def assign_office_infrastructure(cls, instances, **kwargs): @classmethod @transition_action( form_fields={ - 'remarks': { - 'field': forms.CharField(label=_('Remarks')), + "remarks": { + "field": forms.CharField(label=_("Remarks")), } } ) def add_remarks(cls, instances, **kwargs): for instance in instances: - instance.remarks = '{}\n{}'.format( - instance.remarks, kwargs['remarks'] - ) + instance.remarks = "{}\n{}".format(instance.remarks, kwargs["remarks"]) @classmethod @transition_action( form_fields={ - 'task_url': { - 'field': forms.URLField(label=_('task URL')), + "task_url": { + "field": forms.URLField(label=_("task URL")), } } ) def assign_task_url(cls, instances, **kwargs): for instance in instances: - instance.task_url = kwargs['task_url'] + instance.task_url = kwargs["task_url"] @classmethod @transition_action() @@ -466,48 +444,47 @@ def unassign_licences(cls, instances, **kwargs): @classmethod @transition_action( form_fields={ - 'country': { - 'field': forms.ChoiceField( - label=_('Country'), + "country": { + "field": forms.ChoiceField( + label=_("Country"), choices=Country(), **{ - 'initial': Country.from_name( + "initial": Country.from_name( settings.CHANGE_HOSTNAME_ACTION_DEFAULT_COUNTRY.lower() # noqa: E501 ).id } - if settings.CHANGE_HOSTNAME_ACTION_DEFAULT_COUNTRY else {} + if settings.CHANGE_HOSTNAME_ACTION_DEFAULT_COUNTRY + else {}, ), } }, ) def change_hostname(cls, instances, **kwargs): - country_id = kwargs['country'] + country_id = kwargs["country"] country_name = Country.name_from_id(int(country_id)).upper() iso3_country_name = iso2_to_iso3(country_name) for instance in instances: - instance._try_assign_hostname( - country=iso3_country_name, force=True - ) + instance._try_assign_hostname(country=iso3_country_name, force=True) @classmethod @transition_action( form_fields={ - 'user': { - 'field': forms.CharField(label=_('User')), - 'autocomplete_field': 'user', + "user": { + "field": forms.CharField(label=_("User")), + "autocomplete_field": "user", + }, + "owner": { + "field": forms.CharField(label=_("Owner")), + "autocomplete_field": "owner", + "condition": lambda obj, actions: bool(obj.owner), }, - 'owner': { - 'field': forms.CharField(label=_('Owner')), - 'autocomplete_field': 'owner', - 'condition': lambda obj, actions: bool(obj.owner), - } } ) def change_user_and_owner(cls, instances, **kwargs): UserModel = get_user_model() # noqa - user_id = kwargs.get('user', None) + user_id = kwargs.get("user", None) user = UserModel.objects.get(id=user_id) - owner_id = kwargs.get('owner', None) + owner_id = kwargs.get("owner", None) for instance in instances: instance.user = user if not owner_id: @@ -520,11 +497,11 @@ def change_user_and_owner(cls, instances, **kwargs): def _get_report_context(cls, instances): data_instances = [ { - 'sn': obj.sn, - 'model': str(obj.model), - 'imei': obj.imei, - 'imei2': obj.imei2, - 'barcode': obj.barcode, + "sn": obj.sn, + "model": str(obj.model), + "imei": obj.imei, + "imei2": obj.imei2, + "barcode": obj.barcode, } for obj in instances ] @@ -545,11 +522,10 @@ def must_be_user_of_asset(cls, instances, **kwargs): @classmethod @transition_action( form_fields={ - 'accept': { - 'field': forms.BooleanField( + "accept": { + "field": forms.BooleanField( label=_( - 'I have read and fully understand and ' - 'accept the agreement.' + "I have read and fully understand and " "accept the agreement." ) ) }, @@ -559,9 +535,7 @@ def accept_asset_release_agreement(cls, instances, requester, **kwargs): pass @classmethod - @transition_action( - run_after=['release_report'] - ) + @transition_action(run_after=["release_report"]) def assign_requester_as_an_owner(cls, instances, requester, **kwargs): """Assign current user as an owner""" for instance in instances: @@ -571,50 +545,49 @@ def assign_requester_as_an_owner(cls, instances, requester, **kwargs): @classmethod @transition_action( form_fields={ - 'report_language': { - 'field': forms.ModelChoiceField( - label=_('Release report language'), - queryset=ReportLanguage.objects.all().order_by('-default'), - empty_label=None + "report_language": { + "field": forms.ModelChoiceField( + label=_("Release report language"), + queryset=ReportLanguage.objects.all().order_by("-default"), + empty_label=None, ), - 'exclude_from_history': True + "exclude_from_history": True, } }, return_attachment=True, - run_after=['assign_owner', 'assign_user'] + run_after=["assign_owner", "assign_user"], ) def release_report(cls, instances, requester, transition_id, **kwargs): report_name = get_report_name_for_transition_id(transition_id) return generate_report( - instances=instances, name=report_name, requester=requester, - language=kwargs['report_language'], - context=cls._get_report_context(instances) + instances=instances, + name=report_name, + requester=requester, + language=kwargs["report_language"], + context=cls._get_report_context(instances), ) @classmethod - @transition_action(run_after=['release_report', 'return_report', - 'loan_report']) + @transition_action(run_after=["release_report", "return_report", "loan_report"]) def send_attachments_to_user(cls, requester, transition_id, **kwargs): - context_func = get_hook( - 'back_office.transition_action.email_context' - ) + context_func = get_hook("back_office.transition_action.email_context") send_transition_attachments_to_user( requester=requester, transition_id=transition_id, context_func=context_func, - **kwargs + **kwargs, ) @classmethod @transition_action( form_fields={ - 'report_language': { - 'field': forms.ModelChoiceField( - label=_('Return report language'), - queryset=ReportLanguage.objects.all().order_by('-default'), - empty_label=None + "report_language": { + "field": forms.ModelChoiceField( + label=_("Return report language"), + queryset=ReportLanguage.objects.all().order_by("-default"), + empty_label=None, ), - 'exclude_from_history': True + "exclude_from_history": True, }, }, return_attachment=True, @@ -622,84 +595,88 @@ def send_attachments_to_user(cls, requester, transition_id, **kwargs): ) def return_report(cls, instances, requester, **kwargs): return generate_report( - instances=instances, name='return', requester=requester, - language=kwargs['report_language'], - context=cls._get_report_context(instances) + instances=instances, + name="return", + requester=requester, + language=kwargs["report_language"], + context=cls._get_report_context(instances), ) @classmethod @transition_action( form_fields={ - 'report_language': { - 'field': forms.ModelChoiceField( - label=_('Loan report language'), - queryset=ReportLanguage.objects.all().order_by('-default'), - empty_label=None + "report_language": { + "field": forms.ModelChoiceField( + label=_("Loan report language"), + queryset=ReportLanguage.objects.all().order_by("-default"), + empty_label=None, ), - 'exclude_from_history': True + "exclude_from_history": True, } }, return_attachment=True, - run_after=['assign_owner', 'assign_user', 'assign_loan_end_date'] + run_after=["assign_owner", "assign_user", "assign_loan_end_date"], ) def loan_report(cls, instances, requester, **kwargs): return generate_report( - name='loan', requester=requester, instances=instances, - language=kwargs['report_language'], - context=cls._get_report_context(instances) + name="loan", + requester=requester, + instances=instances, + language=kwargs["report_language"], + context=cls._get_report_context(instances), ) @classmethod @transition_action( - verbose_name=_('Convert to DataCenter Asset'), + verbose_name=_("Convert to DataCenter Asset"), disable_save_object=True, only_one_action=True, form_fields={ - 'rack': { - 'field': forms.CharField(label=_('Rack')), - 'autocomplete_field': 'rack', - 'autocomplete_model': 'data_center.DataCenterAsset' + "rack": { + "field": forms.CharField(label=_("Rack")), + "autocomplete_field": "rack", + "autocomplete_model": "data_center.DataCenterAsset", }, - 'position': { - 'field': forms.IntegerField(label=_('Position')), + "position": { + "field": forms.IntegerField(label=_("Position")), }, - 'model': { - 'field': forms.CharField(label=_('Model')), - 'autocomplete_field': 'model', - 'autocomplete_model': 'data_center.DataCenterAsset' + "model": { + "field": forms.CharField(label=_("Model")), + "autocomplete_field": "model", + "autocomplete_model": "data_center.DataCenterAsset", }, - 'service_env': { - 'field': forms.CharField(label=_('Service env')), - 'autocomplete_field': 'service_env', - 'autocomplete_model': 'data_center.DataCenterAsset' - } - } + "service_env": { + "field": forms.CharField(label=_("Service env")), + "autocomplete_field": "service_env", + "autocomplete_model": "data_center.DataCenterAsset", + }, + }, ) def convert_to_data_center_asset(cls, instances, **kwargs): from ralph.data_center.models.physical import DataCenterAsset, Rack # noqa from ralph.back_office.helpers import bo_asset_to_dc_asset_status_converter # noqa + with transaction.atomic(): for i, instance in enumerate(instances): data_center_asset = DataCenterAsset() - data_center_asset.rack = Rack.objects.get(pk=kwargs['rack']) - data_center_asset.position = kwargs['position'] + data_center_asset.rack = Rack.objects.get(pk=kwargs["rack"]) + data_center_asset.position = kwargs["position"] data_center_asset.service_env = ServiceEnvironment.objects.get( - pk=kwargs['service_env'] - ) - data_center_asset.model = AssetModel.objects.get( - pk=kwargs['model'] + pk=kwargs["service_env"] ) + data_center_asset.model = AssetModel.objects.get(pk=kwargs["model"]) target_status = int( - Transition.objects.values_list('target', flat=True).get(pk=kwargs['transition_id']) # noqa + Transition.objects.values_list("target", flat=True).get( + pk=kwargs["transition_id"] + ) # noqa ) data_center_asset.status = bo_asset_to_dc_asset_status_converter( # noqa instance.status, target_status ) move_parents_models( - instance, data_center_asset, - exclude_copy_fields=[ - 'rack', 'model', 'service_env', 'status' - ] + instance, + data_center_asset, + exclude_copy_fields=["rack", "model", "service_env", "status"], ) data_center_asset.save() # Save new asset to list, required to redirect url. @@ -708,9 +685,7 @@ def convert_to_data_center_asset(cls, instances, **kwargs): @classmethod @transition_action() - def assign_hostname_if_empty_or_country_not_match( - cls, instances, **kwargs - ): + def assign_hostname_if_empty_or_country_not_match(cls, instances, **kwargs): if settings.BACK_OFFICE_ASSET_AUTO_ASSIGN_HOSTNAME: for instance in instances: instance._try_assign_hostname(commit=False, force=False) diff --git a/src/ralph/back_office/tests/factories.py b/src/ralph/back_office/tests/factories.py index 4163d10c4c..a98e99c4be 100644 --- a/src/ralph/back_office/tests/factories.py +++ b/src/ralph/back_office/tests/factories.py @@ -9,59 +9,56 @@ from ralph.assets.tests.factories import ( AssetHolderFactory, BackOfficeAssetModelFactory, - BudgetInfoFactory -) -from ralph.back_office.models import ( - BackOfficeAsset, - OfficeInfrastructure, - Warehouse + BudgetInfoFactory, ) +from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse from ralph.security.tests.factories import SecurityScanFactory date_now = datetime.now().date() class OfficeInfrastructureFactory(DjangoModelFactory): - - name = factory.Iterator([ - 'Office infrastructure Poland', 'Office infrastructure Germany', - 'Office infrastructure France', 'Office infrastructure UK' - ]) + name = factory.Iterator( + [ + "Office infrastructure Poland", + "Office infrastructure Germany", + "Office infrastructure France", + "Office infrastructure UK", + ] + ) class Meta: model = OfficeInfrastructure - django_get_or_create = ['name'] + django_get_or_create = ["name"] class WarehouseFactory(DjangoModelFactory): - - name = factory.Iterator([ - 'Warehouse 1', 'Warehouse 2', 'Warehouse 3', 'Warehouse 4' - ]) + name = factory.Iterator( + ["Warehouse 1", "Warehouse 2", "Warehouse 3", "Warehouse 4"] + ) class Meta: model = Warehouse - django_get_or_create = ['name'] + django_get_or_create = ["name"] class BackOfficeAssetFactory(DjangoModelFactory): - - hostname = factory.Sequence(lambda n: 'c%04d' % n) + hostname = factory.Sequence(lambda n: "c%04d" % n) region = factory.SubFactory(RegionFactory) model = factory.SubFactory(BackOfficeAssetModelFactory) warehouse = factory.SubFactory(WarehouseFactory) force_depreciation = False office_infrastructure = factory.SubFactory(OfficeInfrastructureFactory) - sn = factory.Faker('ssn') - barcode = factory.Sequence(lambda n: 'bo' + str(n + 10**8)) - order_no = factory.Sequence(lambda n: 'Order number ' + str(n)) + sn = factory.Faker("ssn") + barcode = factory.Sequence(lambda n: "bo" + str(n + 10**8)) + order_no = factory.Sequence(lambda n: "Order number " + str(n)) budget_info = factory.SubFactory(BudgetInfoFactory) invoice_date = date_now - timedelta(days=15) - invoice_no = factory.Sequence(lambda n: 'Invoice number ' + str(n)) + invoice_no = factory.Sequence(lambda n: "Invoice number " + str(n)) price = FuzzyDecimal(10, 300) - securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object') + securityscan = factory.RelatedFactory(SecurityScanFactory, "base_object") property_of = factory.SubFactory(AssetHolderFactory) class Meta: model = BackOfficeAsset - django_get_or_create = ['sn', 'barcode'] + django_get_or_create = ["sn", "barcode"] diff --git a/src/ralph/back_office/tests/test_api.py b/src/ralph/back_office/tests/test_api.py index 656f7909d5..d67b5942d0 100644 --- a/src/ralph/back_office/tests/test_api.py +++ b/src/ralph/back_office/tests/test_api.py @@ -7,13 +7,10 @@ from ralph.assets.tests.factories import ( AssetHolderFactory, BackOfficeAssetModelFactory, - ServiceEnvironmentFactory + ServiceEnvironmentFactory, ) from ralph.back_office.models import BackOfficeAsset -from ralph.back_office.tests.factories import ( - BackOfficeAssetFactory, - WarehouseFactory -) +from ralph.back_office.tests.factories import BackOfficeAssetFactory, WarehouseFactory class BackOfficeAssetAPITests(RalphAPITestCase): @@ -33,47 +30,41 @@ def setUp(self): def test_get_back_office_assets_list(self): BackOfficeAssetFactory.create_batch(100) - url = reverse('backofficeasset-list') + "?limit=100" + url = reverse("backofficeasset-list") + "?limit=100" with self.assertNumQueries(14): - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], BackOfficeAsset.objects.count() - ) + self.assertEqual(response.data["count"], BackOfficeAsset.objects.count()) def test_get_back_office_asset_details(self): - url = reverse('backofficeasset-detail', args=(self.bo_asset.id,)) - response = self.client.get(url, format='json') + url = reverse("backofficeasset-detail", args=(self.bo_asset.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['hostname'], self.bo_asset.hostname) - self.assertEqual(response.data['user']['id'], self.bo_asset.user.id) - self.assertEqual(response.data['owner']['id'], self.bo_asset.owner.id) - self.assertEqual( - response.data['warehouse']['id'], self.bo_asset.warehouse.id - ) - self.assertEqual( - response.data['model']['id'], self.bo_asset.model.id - ) + self.assertEqual(response.data["hostname"], self.bo_asset.hostname) + self.assertEqual(response.data["user"]["id"], self.bo_asset.user.id) + self.assertEqual(response.data["owner"]["id"], self.bo_asset.owner.id) + self.assertEqual(response.data["warehouse"]["id"], self.bo_asset.warehouse.id) + self.assertEqual(response.data["model"]["id"], self.bo_asset.model.id) def test_create_back_office_asset(self): - region = Region.objects.create(name='EU') - url = reverse('backofficeasset-list') + region = Region.objects.create(name="EU") + url = reverse("backofficeasset-list") data = { - 'hostname': '12345', - 'barcode': '12345', - 'user': self.user1.id, - 'owner': self.superuser.id, - 'region': region.id, - 'warehouse': self.warehouse.id, - 'model': self.model.id, - 'service_env': self.service_env.id, - 'force_depreciation': False, - 'property_of': self.assetHolder.id, + "hostname": "12345", + "barcode": "12345", + "user": self.user1.id, + "owner": self.superuser.id, + "region": region.id, + "warehouse": self.warehouse.id, + "model": self.model.id, + "service_env": self.service_env.id, + "force_depreciation": False, + "property_of": self.assetHolder.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - bo_asset = BackOfficeAsset.objects.get(pk=response.data['id']) - self.assertEqual(bo_asset.hostname, '12345') + bo_asset = BackOfficeAsset.objects.get(pk=response.data["id"]) + self.assertEqual(bo_asset.hostname, "12345") self.assertEqual(bo_asset.user, self.user1) self.assertEqual(bo_asset.owner, self.superuser) self.assertEqual(bo_asset.region, region) @@ -81,54 +72,60 @@ def test_create_back_office_asset(self): self.assertEqual(bo_asset.service_env, self.service_env) def test_create_back_office_asset_without_barcode_sn(self): - region = Region.objects.create(name='EU') - url = reverse('backofficeasset-list') + region = Region.objects.create(name="EU") + url = reverse("backofficeasset-list") data = { - 'hostname': '12345', - 'user': self.user1.id, - 'owner': self.superuser.id, - 'region': region.id, - 'warehouse': self.warehouse.id, - 'model': self.model.id, - 'service_env': self.service_env.id, - 'force_depreciation': False, - 'property_of': self.assetHolder.id, + "hostname": "12345", + "user": self.user1.id, + "owner": self.superuser.id, + "region": region.id, + "warehouse": self.warehouse.id, + "model": self.model.id, + "service_env": self.service_env.id, + "force_depreciation": False, + "property_of": self.assetHolder.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, { - 'sn': ['SN or BARCODE field is required'], - 'barcode': ['SN or BARCODE field is required'], - }) + self.assertEqual( + response.data, + { + "sn": ["SN or BARCODE field is required"], + "barcode": ["SN or BARCODE field is required"], + }, + ) def test_create_back_office_asset_without_property_of(self): - region = Region.objects.create(name='EU') - url = reverse('backofficeasset-list') + region = Region.objects.create(name="EU") + url = reverse("backofficeasset-list") data = { - 'hostname': '12345', - 'user': self.user1.id, - 'owner': self.superuser.id, - 'region': region.id, - 'warehouse': self.warehouse.id, - 'model': self.model.id, - 'service_env': self.service_env.id, - 'force_depreciation': False, - 'sn': 'sn', + "hostname": "12345", + "user": self.user1.id, + "owner": self.superuser.id, + "region": region.id, + "warehouse": self.warehouse.id, + "model": self.model.id, + "service_env": self.service_env.id, + "force_depreciation": False, + "sn": "sn", } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, { - '__all__': ['Property of field is required'], - }) + self.assertEqual( + response.data, + { + "__all__": ["Property of field is required"], + }, + ) def test_patch_back_office_asset(self): - url = reverse('backofficeasset-detail', args=(self.bo_asset.id,)) + url = reverse("backofficeasset-detail", args=(self.bo_asset.id,)) data = { - 'user': self.user2.id, - 'owner': None, - 'force_depreciation': True, + "user": self.user2.id, + "owner": None, + "force_depreciation": True, } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.bo_asset.refresh_from_db() self.assertEqual(self.bo_asset.user, self.user2) diff --git a/src/ralph/back_office/tests/test_helpers.py b/src/ralph/back_office/tests/test_helpers.py index 87108384ce..6ec7da8f6f 100644 --- a/src/ralph/back_office/tests/test_helpers.py +++ b/src/ralph/back_office/tests/test_helpers.py @@ -4,6 +4,5 @@ class TestEmailContext(TestCase): - def test_has_from_field(self): - self.assertIn('from_email', EmailContext._fields) + self.assertIn("from_email", EmailContext._fields) diff --git a/src/ralph/back_office/tests/test_models.py b/src/ralph/back_office/tests/test_models.py index 830ca834de..067158e52a 100644 --- a/src/ralph/back_office/tests/test_models.py +++ b/src/ralph/back_office/tests/test_models.py @@ -2,7 +2,6 @@ from datetime import datetime from unittest.mock import patch -from dateutil.relativedelta import relativedelta from dj.choices import Country from django.conf import settings from django.contrib.auth.models import Permission @@ -21,14 +20,14 @@ BackOfficeAssetModelFactory, CategoryFactory, DataCenterAssetModelFactory, - ServiceEnvironmentFactory + ServiceEnvironmentFactory, ) from ralph.attachments.models import Attachment from ralph.back_office.helpers import EmailContext from ralph.back_office.models import ( _check_assets_owner, BackOfficeAsset, - BackOfficeAssetStatus + BackOfficeAssetStatus, ) from ralph.back_office.tests.factories import BackOfficeAssetFactory from ralph.data_center.models import DataCenterAsset, DataCenterAssetStatus @@ -39,7 +38,7 @@ run_field_transition, Transition, TransitionModel, - TransitionNotAllowedError + TransitionNotAllowedError, ) from ralph.lib.transitions.tests import TransitionTestCase from ralph.licences.tests.factories import LicenceFactory @@ -51,11 +50,10 @@ class HostnameGeneratorTests(RalphTestCase): - @classmethod def setUpClass(cls): super().setUpClass() - cls.region_pl = RegionFactory(name='PL', country=Country.pl) + cls.region_pl = RegionFactory(name="PL", country=Country.pl) cls.region_pl.country = Country.pl cls.region_pl.save() @@ -71,76 +69,66 @@ def _check_hostname_is_generated(self, asset): def test_generate_first_hostname(self): """Scenario: - - none of assets has hostname - - after generate first of asset have XXXYY00001 in hostname field + - none of assets has hostname + - after generate first of asset have XXXYY00001 in hostname field """ - category = CategoryFactory(code='PC') + category = CategoryFactory(code="PC") model = BackOfficeAssetModelFactory(category=category) - asset = BackOfficeAssetFactory( - model=model, hostname='' - ) + asset = BackOfficeAssetFactory(model=model, hostname="") template_vars = { - 'code': asset.model.category.code, - 'country_code': asset.country_code, + "code": asset.model.category.code, + "country_code": asset.country_code, } asset.generate_hostname(template_vars=template_vars) - self.assertEqual(asset.hostname, 'POLPC00001') + self.assertEqual(asset.hostname, "POLPC00001") def test_generate_next_hostname(self): - category = CategoryFactory(code='PC') + category = CategoryFactory(code="PC") model = BackOfficeAssetModelFactory(category=category) - asset = BackOfficeAssetFactory( - model=model, region=self.region_pl, hostname='' - ) - BackOfficeAssetFactory(region=self.region_pl, hostname='POLSW00003') - AssetLastHostname.increment_hostname(prefix='POLPC') - AssetLastHostname.increment_hostname(prefix='POLPC') + asset = BackOfficeAssetFactory(model=model, region=self.region_pl, hostname="") + BackOfficeAssetFactory(region=self.region_pl, hostname="POLSW00003") + AssetLastHostname.increment_hostname(prefix="POLPC") + AssetLastHostname.increment_hostname(prefix="POLPC") template_vars = { - 'code': asset.model.category.code, - 'country_code': asset.country_code, + "code": asset.model.category.code, + "country_code": asset.country_code, } asset.generate_hostname(template_vars=template_vars) - self.assertEqual(asset.hostname, 'POLPC00003') + self.assertEqual(asset.hostname, "POLPC00003") def test_cant_generate_hostname_for_model_without_category(self): model = BackOfficeAssetModelFactory(category=None) - asset = BackOfficeAssetFactory( - model=model, region=self.region_pl, hostname='' - ) + asset = BackOfficeAssetFactory(model=model, region=self.region_pl, hostname="") self._check_hostname_not_generated(asset) def test_can_generate_hostname_for_model_with_hostname(self): - category = CategoryFactory(code='PC') + category = CategoryFactory(code="PC") model = BackOfficeAssetModelFactory(category=category) asset = BackOfficeAssetFactory(model=model, region=self.region_pl) self._check_hostname_is_generated(asset) def test_generate_next_hostname_out_of_range(self): - category = CategoryFactory(code='PC') + category = CategoryFactory(code="PC") model = BackOfficeAssetModelFactory(category=category) - asset = BackOfficeAssetFactory( - model=model, region=self.region_pl, hostname='' - ) - AssetLastHostname.objects.create( - prefix='POLPC', counter=99999 - ) + asset = BackOfficeAssetFactory(model=model, region=self.region_pl, hostname="") + AssetLastHostname.objects.create(prefix="POLPC", counter=99999) template_vars = { - 'code': asset.model.category.code, - 'country_code': asset.country_code, + "code": asset.model.category.code, + "country_code": asset.country_code, } asset.generate_hostname(template_vars=template_vars) - self.assertEqual(asset.hostname, 'POLPC100000') + self.assertEqual(asset.hostname, "POLPC100000") def test_convert_iso2_to_iso3(self): - self.assertEqual(iso2_to_iso3('PL'), 'POL') + self.assertEqual(iso2_to_iso3("PL"), "POL") def test_convert_iso3_to_iso2(self): - self.assertEqual(iso3_to_iso2('POL'), 'PL') + self.assertEqual(iso3_to_iso2("POL"), "PL") def test_validate_imei(self): - bo_asset_failed = BackOfficeAssetFactory(imei='failed', imei2='failed') + bo_asset_failed = BackOfficeAssetFactory(imei="failed", imei2="failed") bo_asset = BackOfficeAssetFactory( - imei='990000862471854', imei2='990000862471854' + imei="990000862471854", imei2="990000862471854" ) self.assertFalse(bo_asset_failed.validate_imei(bo_asset_failed.imei)) @@ -154,9 +142,9 @@ class TestBackOfficeAsset(RalphTestCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.region_pl = RegionFactory(name='PL', country=Country.pl) - cls.region_us = RegionFactory(name='US', country=Country.us) - cls.category = CategoryFactory(code='PC') + cls.region_pl = RegionFactory(name="PL", country=Country.pl) + cls.region_us = RegionFactory(name="US", country=Country.us) + cls.category = CategoryFactory(code="PC") cls.category_without_code = CategoryFactory() cls.model = BackOfficeAssetModelFactory(category=cls.category) cls.model_without_code = BackOfficeAssetModelFactory( @@ -168,110 +156,95 @@ def setUp(self): ASSET_BUYOUT_CATEGORY_TO_MONTHS={str(self.category.pk): 48} ): super().setUp() - AssetLastHostname.objects.create(prefix='POLPC', counter=1000) + AssetLastHostname.objects.create(prefix="POLPC", counter=1000) self.bo_asset = BackOfficeAssetFactory( model=self.model, - hostname='abc', + hostname="abc", region=self.region_pl, ) self.bo_asset_2 = BackOfficeAssetFactory( model=self.model, - hostname='abc2', + hostname="abc2", region=self.region_pl, status=BackOfficeAssetStatus.liquidated.id, - invoice_date=None + invoice_date=None, ) self.bo_asset_3 = BackOfficeAssetFactory( model=self.model, - hostname='abc3', + hostname="abc3", region=self.region_pl, status=BackOfficeAssetStatus.liquidated.id, invoice_date=datetime(2016, 1, 11).date(), - depreciation_rate=50 + depreciation_rate=50, ) self.bo_asset_4 = BackOfficeAssetFactory( model=self.model, - hostname='abc3', + hostname="abc3", region=self.region_pl, status=BackOfficeAssetStatus.liquidated.id, invoice_date=datetime(2016, 1, 11).date(), depreciation_end_date=datetime(2015, 1, 11).date(), - depreciation_rate=50 + depreciation_rate=50, ) self.category_parent = CategoryFactory( - code='Mob1', default_depreciation_rate=30 - ) - self.category_2 = CategoryFactory( - code='Mob2', default_depreciation_rate=25 + code="Mob1", default_depreciation_rate=30 ) + self.category_2 = CategoryFactory(code="Mob2", default_depreciation_rate=25) self.category_3 = CategoryFactory( - code='Mob3', parent=self.category_parent, - default_depreciation_rate=0 + code="Mob3", parent=self.category_parent, default_depreciation_rate=0 ) def test_try_assign_hostname(self): self.bo_asset._try_assign_hostname(commit=True) - self.assertEqual(self.bo_asset.hostname, 'POLPC01001') + self.assertEqual(self.bo_asset.hostname, "POLPC01001") def test_try_assign_hostname_no_change(self): - self.bo_asset.hostname = 'POLPC01001' + self.bo_asset.hostname = "POLPC01001" self.bo_asset.save() self.bo_asset._try_assign_hostname(commit=True) - self.assertEqual(self.bo_asset.hostname, 'POLPC01001') + self.assertEqual(self.bo_asset.hostname, "POLPC01001") def test_try_assign_hostname_no_hostname(self): - self.bo_asset.hostname = '' + self.bo_asset.hostname = "" self.bo_asset.save() self.bo_asset._try_assign_hostname(commit=True) - self.assertEqual(self.bo_asset.hostname, 'POLPC01001') + self.assertEqual(self.bo_asset.hostname, "POLPC01001") def test_try_assign_hostname_forced(self): - self.bo_asset.hostname = 'POLPC001010' + self.bo_asset.hostname = "POLPC001010" self.bo_asset.save() self.bo_asset._try_assign_hostname(commit=True, force=True) - self.assertEqual(self.bo_asset.hostname, 'POLPC01001') + self.assertEqual(self.bo_asset.hostname, "POLPC01001") def test_try_assign_hostname_with_country(self): - self.bo_asset._try_assign_hostname(country='US', commit=True) - self.assertEqual(self.bo_asset.hostname, 'USPC00001') + self.bo_asset._try_assign_hostname(country="US", commit=True) + self.assertEqual(self.bo_asset.hostname, "USPC00001") def test_try_assign_hostname_category_without_code(self): bo_asset_2 = BackOfficeAssetFactory( - model=self.model_without_code, hostname='abcd' + model=self.model_without_code, hostname="abcd" ) bo_asset_2._try_assign_hostname(commit=True) - self.assertEqual(bo_asset_2.hostname, 'abcd') + self.assertEqual(bo_asset_2.hostname, "abcd") def test_get_autocomplete_queryset(self): queryset = BackOfficeAsset.get_autocomplete_queryset() self.assertEqual(1, queryset.count()) def test_buyout_date(self): - self.assertEqual( - self.bo_asset_3.buyout_date, - datetime(2020, 1, 11).date() - ) + self.assertEqual(self.bo_asset_3.buyout_date, datetime(2020, 1, 11).date()) - self.assertEqual( - self.bo_asset_2.buyout_date, - None - ) + self.assertEqual(self.bo_asset_2.buyout_date, None) def test_buyout_date_doesnt_use_depreciation_end_date(self): - self.assertEqual( - self.bo_asset_4.buyout_date, - datetime(2020, 1, 11).date() - ) + self.assertEqual(self.bo_asset_4.buyout_date, datetime(2020, 1, 11).date()) def test_changing_buyout_date(self): new_date = datetime(2020, 5, 11).date() self.bo_asset_3.buyout_date = new_date self.bo_asset_3.save() self.bo_asset_3.refresh_from_db() - self.assertEqual( - self.bo_asset_3.buyout_date, - new_date - ) + self.assertEqual(self.bo_asset_3.buyout_date, new_date) def test_get_depreciation_rate(self): self.assertEqual(self.category_2.get_default_depreciation_rate(), 25) @@ -283,33 +256,33 @@ class TestBackOfficeAssetTransitions(TransitionTestCase, RalphTestCase): def setUpClass(cls): super().setUpClass() cls.user_pl = UserFactory(country=Country.pl) - cls.region_pl = RegionFactory(name='PL', country=Country.pl) - cls.region_us = RegionFactory(name='US', country=Country.us) - cls.region_us_2 = RegionFactory(name='US', country=Country.us) - cls.category = CategoryFactory(code='PC') + cls.region_pl = RegionFactory(name="PL", country=Country.pl) + cls.region_us = RegionFactory(name="US", country=Country.us) + cls.region_us_2 = RegionFactory(name="US", country=Country.us) + cls.category = CategoryFactory(code="PC") cls.model = BackOfficeAssetModelFactory(category=cls.category) def setUp(self): super().setUp() - AssetLastHostname.objects.create(prefix='POLPC', counter=1000) + AssetLastHostname.objects.create(prefix="POLPC", counter=1000) self.bo_asset = BackOfficeAssetFactory( model=self.model, - hostname='abc', + hostname="abc", region=self.region_us, ) self.bo_asset._try_assign_hostname(commit=True, force=True) - self.request = RequestFactory().get('/assets/') + self.request = RequestFactory().get("/assets/") self.request.user = self.user_pl # ugly hack from https://code.djangoproject.com/ticket/17971 - setattr(self.request, 'session', 'session') + setattr(self.request, "session", "session") messages = FallbackStorage(self.request) - setattr(self.request, '_messages', messages) + setattr(self.request, "_messages", messages) def test_convert_to_data_center_asset(self): bo_asset = BackOfficeAssetFactory() transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(bo_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(bo_asset, "status"), source=0, target=0, ) @@ -327,25 +300,21 @@ def test_convert_to_data_center_asset(self): ) dc_asset = DataCenterAsset.objects.get(pk=bo_asset_pk) self.assertEqual(dc_asset.rack.id, rack.id) - self.assertFalse( - BackOfficeAsset.objects.filter(pk=bo_asset_pk).exists() - ) + self.assertFalse(BackOfficeAsset.objects.filter(pk=bo_asset_pk).exists()) self.assertEqual(dc_asset.hostname, hostname) def test_convert_to_data_center_asset_preserves_status_name(self): bo_asset = BackOfficeAssetFactory( - status=BackOfficeAssetStatus.from_name('damaged') + status=BackOfficeAssetStatus.from_name("damaged") ) transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(bo_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(bo_asset, "status"), source=0, target=0, ) bo_asset_pk = bo_asset.pk - bo_asset_status_name = BackOfficeAssetStatus.from_id( - bo_asset.status - ).name + bo_asset_status_name = BackOfficeAssetStatus.from_id(bo_asset.status).name rack = RackFactory() BackOfficeAsset.convert_to_data_center_asset( instances=[bo_asset], @@ -357,9 +326,7 @@ def test_convert_to_data_center_asset_preserves_status_name(self): transition_id=transition.pk, ) dc_asset = DataCenterAsset.objects.get(pk=bo_asset_pk) - dc_asset_status_name = DataCenterAssetStatus.from_id( - dc_asset.status - ).name + dc_asset_status_name = DataCenterAssetStatus.from_id(dc_asset.status).name self.assertEqual(bo_asset_status_name, dc_asset_status_name) def test_convert_to_data_center_asset_uses_default_from_transition(self): @@ -367,18 +334,16 @@ def test_convert_to_data_center_asset_uses_default_from_transition(self): "new" # status name common for dc_asset and bo_asset ).id bo_asset = BackOfficeAssetFactory( - status=BackOfficeAssetStatus.from_name('damaged') + status=BackOfficeAssetStatus.from_name("damaged") ) transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(bo_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(bo_asset, "status"), source=0, target=target_status_id, ) bo_asset_pk = bo_asset.pk - target_status_name = BackOfficeAssetStatus.from_id( - target_status_id - ).name + target_status_name = BackOfficeAssetStatus.from_id(target_status_id).name rack = RackFactory() BackOfficeAsset.convert_to_data_center_asset( instances=[bo_asset], @@ -390,9 +355,7 @@ def test_convert_to_data_center_asset_uses_default_from_transition(self): transition_id=transition.pk, ) dc_asset = DataCenterAsset.objects.get(pk=bo_asset_pk) - dc_asset_status_name = DataCenterAssetStatus.from_id( - dc_asset.status - ).name + dc_asset_status_name = DataCenterAssetStatus.from_id(dc_asset.status).name self.assertEqual(target_status_name, dc_asset_status_name) def test_convert_to_data_center_asset_uses_default_from_settings(self): @@ -400,18 +363,16 @@ def test_convert_to_data_center_asset_uses_default_from_settings(self): settings.CONVERT_TO_DATACENTER_ASSET_DEFAULT_STATUS_ID ).id bo_asset = BackOfficeAssetFactory( - status=BackOfficeAssetStatus.from_name('damaged') + status=BackOfficeAssetStatus.from_name("damaged") ) transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(bo_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(bo_asset, "status"), source=0, target=target_status_id, ) bo_asset_pk = bo_asset.pk - target_status_name = BackOfficeAssetStatus.from_id( - target_status_id - ).name + target_status_name = BackOfficeAssetStatus.from_id(target_status_id).name rack = RackFactory() BackOfficeAsset.convert_to_data_center_asset( instances=[bo_asset], @@ -423,9 +384,7 @@ def test_convert_to_data_center_asset_uses_default_from_settings(self): transition_id=transition.pk, ) dc_asset = DataCenterAsset.objects.get(pk=bo_asset_pk) - dc_asset_status_name = DataCenterAssetStatus.from_id( - dc_asset.status - ).name + dc_asset_status_name = DataCenterAssetStatus.from_id(dc_asset.status).name self.assertEqual(target_status_name, dc_asset_status_name) def test_assign_many_licences(self): @@ -434,7 +393,9 @@ def test_assign_many_licences(self): self.assertFalse(asset.licences.all()) BackOfficeAsset.assign_licence( - instances=[asset], request=None, licences=licences, + instances=[asset], + request=None, + licences=licences, ) self.assertCountEqual( @@ -445,39 +406,39 @@ def test_assign_many_licences(self): def test_change_hostname(self): _, transition, _ = self._create_transition( model=self.bo_asset, - name='test', + name="test", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['change_hostname'] + actions=["change_hostname"], ) run_field_transition( [self.bo_asset], - field='status', + field="status", transition_obj_or_name=transition, - data={'change_hostname__country': Country.pl}, - requester=self.request.user + data={"change_hostname__country": Country.pl}, + requester=self.request.user, ) - self.assertEqual(self.bo_asset.hostname, 'POLPC01001') + self.assertEqual(self.bo_asset.hostname, "POLPC01001") def test_assign_owner(self): _, transition, _ = self._create_transition( model=self.bo_asset, - name='test', + name="test", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['assign_owner'] + actions=["assign_owner"], ) run_field_transition( [self.bo_asset], - field='status', + field="status", transition_obj_or_name=transition, - data={'assign_owner__owner': self.user_pl.id}, - requester=self.request.user + data={"assign_owner__owner": self.user_pl.id}, + requester=self.request.user, ) @override_settings(BACK_OFFICE_ASSET_AUTO_ASSIGN_HOSTNAME=False) def test_assign_hostname_doesnt_assign_hostname_when_its_empty(self): - hostname = '' + hostname = "" self.bo_asset = BackOfficeAssetFactory( model=self.model, hostname=hostname, @@ -485,26 +446,26 @@ def test_assign_hostname_doesnt_assign_hostname_when_its_empty(self): ) _, transition, _ = self._create_transition( model=self.bo_asset, - name='assign_hostname_if_empty_or_country_not_match', + name="assign_hostname_if_empty_or_country_not_match", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['assign_hostname_if_empty_or_country_not_match'] + actions=["assign_hostname_if_empty_or_country_not_match"], ) self.assertEqual(self.bo_asset.hostname, hostname) run_field_transition( [self.bo_asset], - field='status', + field="status", transition_obj_or_name=transition, data={}, - requester=self.request.user + requester=self.request.user, ) self.assertEqual(self.bo_asset.hostname, hostname) @override_settings(BACK_OFFICE_ASSET_AUTO_ASSIGN_HOSTNAME=True) def test_assign_hostname_assigns_hostname_when_its_empty(self): - hostname = '' + hostname = "" self.bo_asset = BackOfficeAssetFactory( model=self.model, hostname=hostname, @@ -512,26 +473,26 @@ def test_assign_hostname_assigns_hostname_when_its_empty(self): ) _, transition, _ = self._create_transition( model=self.bo_asset, - name='assign_hostname_if_empty_or_country_not_match', + name="assign_hostname_if_empty_or_country_not_match", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['assign_hostname_if_empty_or_country_not_match'] + actions=["assign_hostname_if_empty_or_country_not_match"], ) self.assertEqual(self.bo_asset.hostname, hostname) run_field_transition( [self.bo_asset], - field='status', + field="status", transition_obj_or_name=transition, data={}, - requester=self.request.user + requester=self.request.user, ) self.assertNotEquals(self.bo_asset.hostname, hostname) def test_assign_hostname_skips_hostname_when_its_already_set(self): # hostname must include country-code to be skipped during assigning - hostname = 'the-same-hostname-across-transitions-{}'.format('USA') + hostname = "the-same-hostname-across-transitions-{}".format("USA") self.bo_asset = BackOfficeAssetFactory( model=self.model, hostname=hostname, @@ -539,19 +500,19 @@ def test_assign_hostname_skips_hostname_when_its_already_set(self): ) _, transition, _ = self._create_transition( model=self.bo_asset, - name='assign_hostname_if_empty_or_country_not_match', + name="assign_hostname_if_empty_or_country_not_match", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['assign_hostname_if_empty_or_country_not_match'] + actions=["assign_hostname_if_empty_or_country_not_match"], ) self.assertEqual(self.bo_asset.hostname, hostname) run_field_transition( [self.bo_asset], - field='status', + field="status", transition_obj_or_name=transition, data={}, - requester=self.request.user + requester=self.request.user, ) self.assertEqual(self.bo_asset.hostname, hostname) @@ -559,36 +520,32 @@ def test_assign_hostname_skips_hostname_when_its_already_set(self): def test_return_report_when_user_not_assigned(self): _, transition, _ = self._create_transition( model=self.bo_asset, - name='test', + name="test", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['return_report'] + actions=["return_report"], ) with self.assertRaises(TransitionNotAllowedError): _check_instances_for_transition( - instances=[self.bo_asset], - transition=transition, - requester=self.user_pl + instances=[self.bo_asset], transition=transition, requester=self.user_pl ) def test_return_report_when_requester_is_not_assets_owner(self): _, transition, _ = self._create_transition( model=self.bo_asset, - name='test', + name="test", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['must_be_owner_of_asset'] + actions=["must_be_owner_of_asset"], ) with self.assertRaises(TransitionNotAllowedError): _check_instances_for_transition( - instances=[self.bo_asset], - transition=transition, - requester=self.user_pl + instances=[self.bo_asset], transition=transition, requester=self.user_pl ) @patch.object(ExternalService, "run") def test_a_report_is_generated(self, mock_method): - GENERATED_FILE_CONTENT = REPORT_TEMPLATE = b'some-content' + GENERATED_FILE_CONTENT = REPORT_TEMPLATE = b"some-content" mock_method.return_value = GENERATED_FILE_CONTENT report_template = ReportTemplateFactory(template__data=REPORT_TEMPLATE) user = UserFactory() @@ -599,49 +556,49 @@ def test_a_report_is_generated(self, mock_method): ] context = BackOfficeAsset._get_report_context(instances) attachment = generate_report( - report_template.name, user, instances, report_template.language, - context=context) + report_template.name, + user, + instances, + report_template.language, + context=context, + ) - correct_filename = '{}_{}-{}_{}.pdf'.format( - timezone.now().isoformat()[:10], 'james', 'bond', + correct_filename = "{}_{}-{}_{}.pdf".format( + timezone.now().isoformat()[:10], + "james", + "bond", report_template.report.name, ) self.assertEqual(len(attachment), 1) self.assertEqual(attachment[0].original_filename, correct_filename) self.assertEqual(attachment[0].file.read(), GENERATED_FILE_CONTENT) - @patch.object(ralph.back_office.models, 'get_hook') + @patch.object(ralph.back_office.models, "get_hook") def test_send_attachments_to_user_action_sends_email(self, mock_get_hook): mock_get_hook.return_value = lambda transition_name: EmailContext( - from_email="foo@bar.pl", - subject="sub", - body="bod" + from_email="foo@bar.pl", subject="sub", body="bod" ) bo_asset = BackOfficeAssetFactory(model=self.model) _, transition, _ = self._create_transition( model=bo_asset, - name='transition name', + name="transition name", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['return_report'] + actions=["return_report"], ) attachment = Attachment.objects.create( file=SimpleUploadedFile( - 'test_file.pdf', - b'some content', - content_type='application/pdf' + "test_file.pdf", b"some content", content_type="application/pdf" ), uploaded_by=self.user_pl, ) bo_asset.send_attachments_to_user( - self.user_pl, - transition.id, - attachments=[attachment] + self.user_pl, transition.id, attachments=[attachment] ) mock_get_hook.assert_called_once_with( - 'back_office.transition_action.email_context' + "back_office.transition_action.email_context" ) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].from_email, "foo@bar.pl") @@ -650,10 +607,10 @@ def test_send_attachments_to_user_action_dont_send_email_without_attachments(sel bo_asset = BackOfficeAssetFactory(model=self.model) _, transition, _ = self._create_transition( model=self.bo_asset, - name='transition name', + name="transition name", source=[BackOfficeAssetStatus.new.id], target=BackOfficeAssetStatus.used.id, - actions=['return_report'] + actions=["return_report"], ) bo_asset.send_attachments_to_user(self.user_pl, transition.id) @@ -664,26 +621,25 @@ def test_send_attachments_to_user_action_dont_send_email_without_attachments(sel class CheckerTestCase(SimpleTestCase): def test_requester_must_be_specified(self): errors = _check_assets_owner(instances=[], requester=None) - self.assertTrue('__all__' in errors) + self.assertTrue("__all__" in errors) class BackOfficeAssetFormTest(TransitionTestCase, ClientMixin): - def setUp(self): super().setUp() self.asset = BackOfficeAssetFactory() self.user = UserFactory() self.user.is_superuser = False self.user.is_staff = True - self.passwd = 'ralph' + self.passwd = "ralph" self.user.set_password(self.passwd) # Grant all permissions to the user permissions = Permission.objects.exclude( codename__in=[ - 'view_backofficeasset_hostname_field', - 'view_backofficeasset_service_env_field', - 'change_backofficeasset_hostname_field', - 'change_backofficeasset_service_env_field', + "view_backofficeasset_hostname_field", + "view_backofficeasset_service_env_field", + "change_backofficeasset_hostname_field", + "change_backofficeasset_service_env_field", ] ).all() @@ -692,80 +648,63 @@ def setUp(self): self.user.save() self.login_as_user(user=self.user, password=self.passwd) self.data = { - 'hostname': self.asset.hostname, - 'model': self.asset.model.pk, - 'status': self.asset.status, - 'warehouse': self.asset.warehouse.pk, - 'region': self.asset.region.pk, - 'barcode': self.asset.barcode, - 'depreciation_rate': 0, - 'property_of': self.asset.property_of.id, - 'custom_fields-customfieldvalue-content_type-object_id-INITIAL_FORMS': '0', # noqa: E501 - 'custom_fields-customfieldvalue-content_type-object_id-MAX_NUM_FORMS': '1000', # noqa: E501 - 'custom_fields-customfieldvalue-content_type-object_id-MIN_NUM_FORMS': '0', # noqa: E501 - 'custom_fields-customfieldvalue-content_type-object_id-TOTAL_FORMS': '3', # noqa: E501fhtml + "hostname": self.asset.hostname, + "model": self.asset.model.pk, + "status": self.asset.status, + "warehouse": self.asset.warehouse.pk, + "region": self.asset.region.pk, + "barcode": self.asset.barcode, + "depreciation_rate": 0, + "property_of": self.asset.property_of.id, + "custom_fields-customfieldvalue-content_type-object_id-INITIAL_FORMS": "0", # noqa: E501 + "custom_fields-customfieldvalue-content_type-object_id-MAX_NUM_FORMS": "1000", # noqa: E501 + "custom_fields-customfieldvalue-content_type-object_id-MIN_NUM_FORMS": "0", # noqa: E501 + "custom_fields-customfieldvalue-content_type-object_id-TOTAL_FORMS": "3", # noqa: E501fhtml } def test_bo_admin_form_wo_access_to_service_env_and_hostname(self): - url = reverse( - 'admin:back_office_backofficeasset_change', - args=(self.asset.pk,) - ) + url = reverse("admin:back_office_backofficeasset_change", args=(self.asset.pk,)) resp = self.client.get(url, follow=True) self.assertEqual(resp.status_code, 200) - self.assertIn('model', resp.context['adminform'].form.fields) - self.assertNotIn('hostname', resp.context['adminform'].form.fields) - self.assertNotIn('service_env', resp.context['adminform'].form.fields) + self.assertIn("model", resp.context["adminform"].form.fields) + self.assertNotIn("hostname", resp.context["adminform"].form.fields) + self.assertNotIn("service_env", resp.context["adminform"].form.fields) @override_settings(BACKOFFICE_HOSTNAME_FIELD_READONLY=True) def test_bo_admin_form_with_readonly_hostname(self): self.assertTrue(self.login_as_user()) asset = BackOfficeAssetFactory() - url = reverse( - 'admin:back_office_backofficeasset_change', - args=(asset.pk,) - ) + url = reverse("admin:back_office_backofficeasset_change", args=(asset.pk,)) resp = self.client.get(url, follow=True) self.assertEqual(resp.status_code, 200) - self.assertIn('hostname', resp.context['adminform'].form.fields) + self.assertIn("hostname", resp.context["adminform"].form.fields) self.assertTrue( - resp.context['adminform'].form.fields['hostname'].widget.attrs.get( - 'readonly' - ) + resp.context["adminform"] + .form.fields["hostname"] + .widget.attrs.get("readonly") ) def test_model_asset_type_back_office_shall_pass(self): back_office_model = DataCenterAssetModelFactory( - type=ObjectModelType.from_name('back_office') - ) - self.data.update({ - 'model': back_office_model.pk - }) - response = self.client.post( - self.asset.get_absolute_url(), self.data + type=ObjectModelType.from_name("back_office") ) + self.data.update({"model": back_office_model.pk}) + response = self.client.post(self.asset.get_absolute_url(), self.data) self.asset.refresh_from_db() self.assertEqual(response.status_code, 302) self.assertEqual(self.asset.model, back_office_model) def test_model_asset_type_data_center_asset_shall_not_pass(self): back_office_model = DataCenterAssetModelFactory( - type=ObjectModelType.from_name('data_center') - ) - self.data.update({ - 'model': back_office_model.pk - }) - response = self.client.post( - self.asset.get_absolute_url(), self.data + type=ObjectModelType.from_name("data_center") ) + self.data.update({"model": back_office_model.pk}) + response = self.client.post(self.asset.get_absolute_url(), self.data) self.asset.refresh_from_db() - self.assertIn( - 'Model must be of', - response.content.decode('utf-8') - ) + self.assertIn("Model must be of", response.content.decode("utf-8")) self.assertNotEqual(self.asset.model, back_office_model) self.assertEqual(response.status_code, 200) diff --git a/src/ralph/back_office/views.py b/src/ralph/back_office/views.py index a68905fe31..aa19c5b48c 100644 --- a/src/ralph/back_office/views.py +++ b/src/ralph/back_office/views.py @@ -3,75 +3,69 @@ class BackOfficeAssetComponents(RalphDetailView): - - icon = 'folder' - name = 'components' - label = 'Components' - url_name = 'back_office_asset_components' + icon = "folder" + name = "components" + label = "Components" + url_name = "back_office_asset_components" def get_context_data(self, **kwargs): - context = super(BackOfficeAssetComponents, self).get_context_data( - **kwargs - ) - context['components'] = [ + context = super(BackOfficeAssetComponents, self).get_context_data(**kwargs) + context["components"] = [ { - 'label': 'CPU 1', - 'model': 'Intel(R) Xeon(R) CPU E5540 @ 2.53GHz', - 'serial_number': '', - 'speed': '2415 Mhz', - 'size': '4 core(s)', - 'count': '', - 'action': '', + "label": "CPU 1", + "model": "Intel(R) Xeon(R) CPU E5540 @ 2.53GHz", + "serial_number": "", + "speed": "2415 Mhz", + "size": "4 core(s)", + "count": "", + "action": "", }, { - 'label': 'HDD', - 'model': 'Baracuda', - 'serial_number': 'SN/JKIO9009KL', - 'speed': '', - 'size': '120 GB', - 'count': '1', - 'action': '', + "label": "HDD", + "model": "Baracuda", + "serial_number": "SN/JKIO9009KL", + "speed": "", + "size": "120 GB", + "count": "1", + "action": "", }, { - 'label': 'RAM', - 'model': 'Kingston', - 'serial_number': 'SN/JKIO9009KDS', - 'speed': '', - 'size': '8 GB', - 'count': '1', - 'action': '', + "label": "RAM", + "model": "Kingston", + "serial_number": "SN/JKIO9009KDS", + "speed": "", + "size": "8 GB", + "count": "1", + "action": "", }, ] return context class BackOfficeAssetSoftware(RalphDetailView): - - icon = 'wrench' - name = 'software' - label = 'Software' - url_name = 'back_office_asset_software' + icon = "wrench" + name = "software" + label = "Software" + url_name = "back_office_asset_software" def get_context_data(self, **kwargs): - context = super(BackOfficeAssetSoftware, self).get_context_data( - **kwargs - ) - context['software_list'] = [ + context = super(BackOfficeAssetSoftware, self).get_context_data(**kwargs) + context["software_list"] = [ { - 'label': 'Windows', - 'version': '8', + "label": "Windows", + "version": "8", }, { - 'label': 'OpenOffice', - 'version': '2.5.6', + "label": "OpenOffice", + "version": "2.5.6", }, { - 'label': 'HipChat', - 'version': '50.6.0', + "label": "HipChat", + "version": "50.6.0", }, { - 'label': 'ESET NOD32', - 'version': '1.5.0', + "label": "ESET NOD32", + "version": "1.5.0", }, ] return context diff --git a/src/ralph/configuration_management/api.py b/src/ralph/configuration_management/api.py index 2b081e2c97..2370edc62a 100644 --- a/src/ralph/configuration_management/api.py +++ b/src/ralph/configuration_management/api.py @@ -20,9 +20,8 @@ class Meta: class SCMInfoSaveSerializer(RalphAPISaveSerializer): - class Meta: - fields = ('last_checked', 'check_result') + fields = ("last_checked", "check_result") model = SCMStatusCheck @@ -31,24 +30,21 @@ class SCMInfoViewSet(RalphAPIViewSet): serializer_class = SCMInfoSerializer save_serializer_class = SCMInfoSaveSerializer - select_related = ['base_object'] + select_related = ["base_object"] def get_baseobject(self, hostname): fields = [ - 'asset__hostname', - 'cloudhost__hostname', - 'cluster__hostname', - 'virtualserver__hostname', + "asset__hostname", + "cloudhost__hostname", + "cluster__hostname", + "virtualserver__hostname", ] - queries = [ - Q(**{field: hostname.strip()}) - for field in fields - ] + queries = [Q(**{field: hostname.strip()}) for field in fields] - return BaseObject.objects.filter( - reduce(operator.or_, queries) - ).distinct().first() + return ( + BaseObject.objects.filter(reduce(operator.or_, queries)).distinct().first() + ) def delete(self, request, hostname): """Cleans up SCM scan record for an object having matching hostname.""" @@ -57,16 +53,16 @@ def delete(self, request, hostname): if bo is None: return Response( - 'No hostname matching {} found.'.format(hostname), - status.HTTP_404_NOT_FOUND + "No hostname matching {} found.".format(hostname), + status.HTTP_404_NOT_FOUND, ) try: bo.scmstatuscheck.delete() except ObjectDoesNotExist: return Response( - 'SCM status is not set for the hostname {}'.format(hostname), - status=status.HTTP_404_NOT_FOUND + "SCM status is not set for the hostname {}".format(hostname), + status=status.HTTP_404_NOT_FOUND, ) return Response(status=status.HTTP_204_NO_CONTENT) @@ -78,21 +74,20 @@ def create(self, request, hostname): if bo is None: return Response( - 'No hostname matching {} found.'.format(hostname), - status.HTTP_404_NOT_FOUND + "No hostname matching {} found.".format(hostname), + status.HTTP_404_NOT_FOUND, ) serializer = self.save_serializer_class(data=request.data) serializer.is_valid(raise_exception=True) update_data = { - 'last_checked': serializer.validated_data['last_checked'], - 'check_result': serializer.validated_data['check_result'] + "last_checked": serializer.validated_data["last_checked"], + "check_result": serializer.validated_data["check_result"], } scan, created = SCMStatusCheck.objects.update_or_create( - base_object_id=bo.id, - defaults=update_data + base_object_id=bo.id, defaults=update_data ) res_status = status.HTTP_201_CREATED if created else status.HTTP_200_OK @@ -100,11 +95,11 @@ def create(self, request, hostname): return Response(self.serializer_class(scan).data, status=res_status) -router.register('scm-info', SCMInfoViewSet) +router.register("scm-info", SCMInfoViewSet) urlpatterns = [ url( - r'^scm-info/(?P[\w\.-]+)', - SCMInfoViewSet.as_view({'post': 'create', 'delete': 'delete'}), - name='scm-info-post' + r"^scm-info/(?P[\w\.-]+)", + SCMInfoViewSet.as_view({"post": "create", "delete": "delete"}), + name="scm-info-post", ) ] diff --git a/src/ralph/configuration_management/migrations/0001_initial.py b/src/ralph/configuration_management/migrations/0001_initial.py index da7ff439b6..8a8653b6d2 100644 --- a/src/ralph/configuration_management/migrations/0001_initial.py +++ b/src/ralph/configuration_management/migrations/0001_initial.py @@ -6,24 +6,51 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0026_auto_20170510_0840'), + ("assets", "0026_auto_20170510_0840"), ] operations = [ migrations.CreateModel( - name='SCMStatusCheck', + name="SCMStatusCheck", fields=[ - ('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('last_checked', models.DateTimeField(verbose_name='Last SCM check')), - ('check_result', models.PositiveIntegerField(choices=[(1, 'OK'), (2, 'Check failed'), (3, 'Error')], verbose_name='SCM check result')), - ('base_object', models.OneToOneField(to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + auto_created=True, + verbose_name="ID", + serialize=False, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ("last_checked", models.DateTimeField(verbose_name="Last SCM check")), + ( + "check_result", + models.PositiveIntegerField( + choices=[(1, "OK"), (2, "Check failed"), (3, "Error")], + verbose_name="SCM check result", + ), + ), + ( + "base_object", + models.OneToOneField( + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), ] diff --git a/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py b/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py index e1b60501eb..5ab3e7f586 100644 --- a/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py +++ b/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py @@ -1,21 +1,23 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.configuration_management.models import dj.choices.fields class Migration(migrations.Migration): - dependencies = [ - ('configuration_management', '0001_initial'), + ("configuration_management", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='scmstatuscheck', - name='check_result', - field=dj.choices.fields.ChoiceField(verbose_name='SCM check result', choices=ralph.configuration_management.models.SCMCheckResult), + model_name="scmstatuscheck", + name="check_result", + field=dj.choices.fields.ChoiceField( + verbose_name="SCM check result", + choices=ralph.configuration_management.models.SCMCheckResult, + ), ), ] diff --git a/src/ralph/configuration_management/migrations/0003_scmstatuscheck_ok.py b/src/ralph/configuration_management/migrations/0003_scmstatuscheck_ok.py index 7e6f04c3ce..8510bfabf1 100644 --- a/src/ralph/configuration_management/migrations/0003_scmstatuscheck_ok.py +++ b/src/ralph/configuration_management/migrations/0003_scmstatuscheck_ok.py @@ -5,24 +5,20 @@ def populate_ok_field(apps, schema_editor): - SCMStatusCheck = apps.get_model('configuration_management', 'SCMStatusCheck') + SCMStatusCheck = apps.get_model("configuration_management", "SCMStatusCheck") SCMStatusCheck.objects.filter(check_result=1).update(ok=True) class Migration(migrations.Migration): - dependencies = [ - ('configuration_management', '0002_auto_20170622_1254'), + ("configuration_management", "0002_auto_20170622_1254"), ] operations = [ migrations.AddField( - model_name='scmstatuscheck', - name='ok', + model_name="scmstatuscheck", + name="ok", field=models.BooleanField(editable=False, default=False), ), - migrations.RunPython( - populate_ok_field, - reverse_code=migrations.RunPython.noop - ) + migrations.RunPython(populate_ok_field, reverse_code=migrations.RunPython.noop), ] diff --git a/src/ralph/configuration_management/models.py b/src/ralph/configuration_management/models.py index 4be83267e2..a41f4f0165 100644 --- a/src/ralph/configuration_management/models.py +++ b/src/ralph/configuration_management/models.py @@ -11,34 +11,25 @@ class SCMCheckResult(Choices): _ = Choices.Choice - scm_ok = _("OK").extra(alert='success', icon_class='fa-check-circle') + scm_ok = _("OK").extra(alert="success", icon_class="fa-check-circle") check_failed = _("Check failed").extra( - alert='warning', - icon_class='fa-question-circle' - ) - scm_error = _("Error").extra( - alert='alert', - icon_class='fa-exclamation-triangle' + alert="warning", icon_class="fa-question-circle" ) + scm_error = _("Error").extra(alert="alert", icon_class="fa-exclamation-triangle") -class SCMStatusCheck( - PermByFieldMixin, - TimeStampMixin, - models.Model -): +class SCMStatusCheck(PermByFieldMixin, TimeStampMixin, models.Model): """Represents software configuration management scan.""" base_object = models.OneToOneField(BaseObject, on_delete=models.CASCADE) last_checked = models.DateTimeField( - blank=False, null=False, - verbose_name=_("Last SCM check") + blank=False, null=False, verbose_name=_("Last SCM check") ) check_result = ChoiceField( choices=SCMCheckResult, blank=False, null=False, - verbose_name=_("SCM check result") + verbose_name=_("SCM check result"), ) ok = models.BooleanField(default=False, editable=False) diff --git a/src/ralph/configuration_management/tests/factories.py b/src/ralph/configuration_management/tests/factories.py index 9bbe0a9db3..e3eb648bef 100644 --- a/src/ralph/configuration_management/tests/factories.py +++ b/src/ralph/configuration_management/tests/factories.py @@ -7,7 +7,6 @@ class SCMStatusCheckFactory(DjangoModelFactory): - last_checked = factory.LazyFunction(datetime.now) check_result = SCMCheckResult.scm_ok diff --git a/src/ralph/configuration_management/tests/test_api.py b/src/ralph/configuration_management/tests/test_api.py index e3316738b1..a27a1b04c7 100644 --- a/src/ralph/configuration_management/tests/test_api.py +++ b/src/ralph/configuration_management/tests/test_api.py @@ -10,47 +10,30 @@ class TestSCMScanAPI(RalphAPITestCase): - def test_post_by_hostname_creates_scm_status_record(self): v_server = VirtualServerFullFactory() - url = reverse( - 'scm-info-post', - kwargs={'hostname': v_server.hostname} - ) + url = reverse("scm-info-post", kwargs={"hostname": v_server.hostname}) data = { - 'last_checked': datetime.now().isoformat(), - 'check_result': SCMCheckResult.scm_ok.id + "last_checked": datetime.now().isoformat(), + "check_result": SCMCheckResult.scm_ok.id, } resp = self.client.post(url, data=data) self.assertEqual(resp.status_code, 201) - self.assertEqual( - resp.data.get('base_object'), - v_server.baseobject_ptr_id - ) - self.assertEqual( - resp.data.get('check_result'), - SCMCheckResult.scm_ok.raw - ) - self.assertEqual( - resp.data.get('last_checked'), - data['last_checked'] - ) + self.assertEqual(resp.data.get("base_object"), v_server.baseobject_ptr_id) + self.assertEqual(resp.data.get("check_result"), SCMCheckResult.scm_ok.raw) + self.assertEqual(resp.data.get("last_checked"), data["last_checked"]) def test_delete_scm_status_record(self): v_server = VirtualServerFullFactory() existing_scan = SCMStatusCheckFactory( - base_object=v_server.baseobject_ptr, - check_result=SCMCheckResult.scm_ok + base_object=v_server.baseobject_ptr, check_result=SCMCheckResult.scm_ok ) - url = reverse( - 'scm-info-post', - kwargs={'hostname': v_server.hostname} - ) + url = reverse("scm-info-post", kwargs={"hostname": v_server.hostname}) resp = self.client.delete(url) self.assertEqual(resp.status_code, 204) @@ -59,10 +42,7 @@ def test_delete_scm_status_record(self): SCMStatusCheck.objects.get(pk=existing_scan.pk) def test_delete_wrong_hostname_returns_404(self): - url = reverse( - 'scm-info-post', - kwargs={'hostname': 'deadbeef.local'} - ) + url = reverse("scm-info-post", kwargs={"hostname": "deadbeef.local"}) resp = self.client.delete(url) self.assertEqual(resp.status_code, 404) @@ -70,10 +50,7 @@ def test_delete_wrong_hostname_returns_404(self): def test_delete_non_existing_scm_status_record_returns_404(self): v_server = VirtualServerFullFactory() - url = reverse( - 'scm-info-post', - kwargs={'hostname': v_server.hostname} - ) + url = reverse("scm-info-post", kwargs={"hostname": v_server.hostname}) resp = self.client.delete(url) self.assertEqual(resp.status_code, 404) @@ -81,79 +58,55 @@ def test_delete_non_existing_scm_status_record_returns_404(self): def test_post_by_hostname_updates_scm_status_record(self): v_server = VirtualServerFullFactory() existing_scan = SCMStatusCheckFactory( - base_object=v_server.baseobject_ptr, - check_result=SCMCheckResult.scm_ok + base_object=v_server.baseobject_ptr, check_result=SCMCheckResult.scm_ok ) - url = reverse( - 'scm-info-post', - kwargs={'hostname': v_server.hostname} - ) + url = reverse("scm-info-post", kwargs={"hostname": v_server.hostname}) data = { - 'last_checked': datetime.now().isoformat(), - 'check_result': SCMCheckResult.check_failed.id + "last_checked": datetime.now().isoformat(), + "check_result": SCMCheckResult.check_failed.id, } resp = self.client.post(url, data=data) self.assertEqual(resp.status_code, 200) updated_scan = SCMStatusCheck.objects.get(pk=existing_scan.pk) - self.assertEqual( - updated_scan.check_result, - SCMCheckResult.check_failed - ) + self.assertEqual(updated_scan.check_result, SCMCheckResult.check_failed) self.assertFalse(updated_scan.ok) - self.assertEqual( - resp.data.get('base_object'), - existing_scan.base_object_id - ) - self.assertEqual( - resp.data.get('check_result'), - SCMCheckResult.check_failed.raw - ) - self.assertEqual( - resp.data.get('last_checked'), - data['last_checked'] - ) + self.assertEqual(resp.data.get("base_object"), existing_scan.base_object_id) + self.assertEqual(resp.data.get("check_result"), SCMCheckResult.check_failed.raw) + self.assertEqual(resp.data.get("last_checked"), data["last_checked"]) def test_double_post_does_not_create_duplicate_scm_status_record(self): v_server = VirtualServerFullFactory() - url = reverse( - 'scm-info-post', - kwargs={'hostname': v_server.hostname} - ) + url = reverse("scm-info-post", kwargs={"hostname": v_server.hostname}) data = { - 'last_checked': datetime.now().isoformat(), - 'check_result': SCMCheckResult.check_failed.id + "last_checked": datetime.now().isoformat(), + "check_result": SCMCheckResult.check_failed.id, } resp = self.client.post(url, data=data) self.assertEqual(resp.status_code, 201) data = { - 'last_checked': datetime.now().isoformat(), - 'check_result': SCMCheckResult.check_failed.id + "last_checked": datetime.now().isoformat(), + "check_result": SCMCheckResult.check_failed.id, } resp = self.client.post(url, data=data) self.assertEqual(resp.status_code, 200) - self.assertEqual( - len(SCMStatusCheck.objects.all()), 1 - ) + self.assertEqual(len(SCMStatusCheck.objects.all()), 1) def test_post_wrong_hostname_returns_404(self): - url = reverse( - 'scm-info-post', - kwargs={'hostname': 'deadbeef.local'} - ) + url = reverse("scm-info-post", kwargs={"hostname": "deadbeef.local"}) data = { - 'last_checked': datetime.now().isoformat(), - 'check_result': SCMCheckResult.check_failed.id + "last_checked": datetime.now().isoformat(), + "check_result": SCMCheckResult.check_failed.id, } resp = self.client.post(url, data=data) @@ -163,21 +116,15 @@ def test_creating_scm_status_record_ignores_baseobject_id_in_data(self): v_server_1 = VirtualServerFullFactory() v_server_2 = VirtualServerFullFactory() - url = reverse( - 'scm-info-post', - kwargs={'hostname': v_server_1.hostname} - ) + url = reverse("scm-info-post", kwargs={"hostname": v_server_1.hostname}) data = { - 'last_checked': datetime.now().isoformat(), - 'check_result': SCMCheckResult.check_failed.id, - 'base_object': v_server_2.baseobject_ptr_id + "last_checked": datetime.now().isoformat(), + "check_result": SCMCheckResult.check_failed.id, + "base_object": v_server_2.baseobject_ptr_id, } resp = self.client.post(url, data=data) self.assertEqual(resp.status_code, 201) - self.assertEqual( - resp.data.get('base_object'), - v_server_1.baseobject_ptr_id - ) + self.assertEqual(resp.data.get("base_object"), v_server_1.baseobject_ptr_id) diff --git a/src/ralph/configuration_management/views.py b/src/ralph/configuration_management/views.py index 44bbd9ba2c..735ed41488 100644 --- a/src/ralph/configuration_management/views.py +++ b/src/ralph/configuration_management/views.py @@ -10,6 +10,7 @@ from ralph.admin.helpers import get_admin_url from ralph.admin.views.extra import RalphDetailView from ralph.configuration_management.models import SCMCheckResult + # NOTE(romcheg): These functions could be moved to a common place from ralph.security.views import _linkify, _url_name_for_change_view @@ -18,12 +19,11 @@ class SCMCheckInfo(RalphDetailView): - - icon = 'cogs' - label = 'SCM info' - name = 'scm_info' + icon = "cogs" + label = "SCM info" + name = "scm_info" url_name = None - template_name = 'configuration_management/scminfo/scm_info.html' + template_name = "configuration_management/scminfo/scm_info.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -31,54 +31,46 @@ def get_context_data(self, **kwargs): check = self.object.scmstatuscheck except ObjectDoesNotExist: check = None - context['scm_check'] = check + context["scm_check"] = check - hostname = getattr(self.object, 'hostname', None) + hostname = getattr(self.object, "hostname", None) if hostname: - context['scm_tool_url'] = settings.SCM_TOOL_URL.format( - hostname=hostname - ) + context["scm_tool_url"] = settings.SCM_TOOL_URL.format(hostname=hostname) return context class SCMStatusCheckInChangeListMixin(object): - - icon_no_scan = '-' + icon_no_scan = "-" icon_scan = '' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.list_select_related += ['scmstatuscheck', ] + self.list_select_related += [ + "scmstatuscheck", + ] self.list_filter += [ - ( - 'scmstatuscheck__check_result', - custom_title_filter('SCM scan status') - ), - ( - 'scmstatuscheck__last_checked', - custom_title_filter('Last SCM scan date') - ) + ("scmstatuscheck__check_result", custom_title_filter("SCM scan status")), + ("scmstatuscheck__last_checked", custom_title_filter("Last SCM scan date")), ] def _to_span(self, css, text): - return'{}'.format(css, text) + return '{}'.format(css, text) def scm_status_check(self, obj): try: scmstatuscheck = obj.scmstatuscheck except ObjectDoesNotExist: - html = self._to_span('', self.icon_no_scan) + html = self._to_span("", self.icon_no_scan) else: check_result = SCMCheckResult.from_id(scmstatuscheck.check_result) html = self._to_span( - check_result.alert, - self.icon_scan.format(check_result.icon_class) + check_result.alert, self.icon_scan.format(check_result.icon_class) ) - url_name = _url_name_for_change_view(type(obj), 'scm_info') + url_name = _url_name_for_change_view(type(obj), "scm_info") if not url_name: logger.error("No scm info view for obj of type: %s", type(obj)) @@ -87,9 +79,8 @@ def scm_status_check(self, obj): url = get_admin_url(obj, url_name) html = _linkify(html, url) except NoReverseMatch: - logger.error( - "cant reverse url for: %s, %s", obj, url_name - ) + logger.error("cant reverse url for: %s, %s", obj, url_name) return mark_safe(html) - scm_status_check.short_description = _('SCM status') - scm_status_check.admin_order_field = 'scmstatuscheck' + + scm_status_check.short_description = _("SCM status") + scm_status_check.admin_order_field = "scmstatuscheck" diff --git a/src/ralph/dashboards/admin.py b/src/ralph/dashboards/admin.py index a37cfa582f..a56e4e1236 100644 --- a/src/ralph/dashboards/admin.py +++ b/src/ralph/dashboards/admin.py @@ -17,101 +17,113 @@ class GraphForm(RalphAdminForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) choices = [ - ct for ct in ContentType.objects.all() - if getattr(ct.model_class(), '_allow_in_dashboard', False) + ct + for ct in ContentType.objects.all() + if getattr(ct.model_class(), "_allow_in_dashboard", False) ] def keyfunc(x): return x.app_label data = sorted(choices, key=keyfunc) - self.fields['model'] = forms.ChoiceField(choices=( - (k.capitalize(), list(map(lambda x: (x.id, x), g))) - for k, g in groupby(data, keyfunc) - )) - - self.initial['params'] = json.dumps( - self.initial.get('params', {}), - indent=4, - sort_keys=True + self.fields["model"] = forms.ChoiceField( + choices=( + (k.capitalize(), list(map(lambda x: (x.id, x), g))) + for k, g in groupby(data, keyfunc) + ) + ) + + self.initial["params"] = json.dumps( + self.initial.get("params", {}), indent=4, sort_keys=True ) def clean_model(self): - ct_id = self.cleaned_data.get('model') + ct_id = self.cleaned_data.get("model") return ContentType.objects.get_for_id(id=ct_id) def clean_params(self): - params = self.cleaned_data.get('params', '{}') + params = self.cleaned_data.get("params", "{}") try: params_dict = json.loads(params) except ValueError as e: raise forms.ValidationError(str(e)) - if not params_dict.get('labels', None): - raise forms.ValidationError('Please specify `labels` key') - if not params_dict.get('series', None): - raise forms.ValidationError('Please specify `series` key') + if not params_dict.get("labels", None): + raise forms.ValidationError("Please specify `labels` key") + if not params_dict.get("series", None): + raise forms.ValidationError("Please specify `series` key") return params class Meta: model = Graph fields = [ - 'name', 'description', 'model', 'aggregate_type', 'chart_type', - 'params', 'active' + "name", + "description", + "model", + "aggregate_type", + "chart_type", + "params", + "active", ] class Media: - js = ( - 'vendor/js/chartist.js', - 'js/chartist-plugin-barlabels.js' - ) + js = ("vendor/js/chartist.js", "js/chartist-plugin-barlabels.js") @register(Graph) class GraphAdmin(RalphAdmin): form = GraphForm - list_display = ['name', 'description', 'active'] - readonly_fields = ['get_preview'] + list_display = ["name", "description", "active"] + readonly_fields = ["get_preview"] fieldsets = ( - (None, { - 'fields': ( - 'name', - 'description', - 'model', - 'aggregate_type', - 'chart_type', - 'params', - 'active', - 'push_to_statsd', - ) - }), - ('Preview', { - 'fields': ('get_preview',), - }), + ( + None, + { + "fields": ( + "name", + "description", + "model", + "aggregate_type", + "chart_type", + "params", + "active", + "push_to_statsd", + ) + }, + ), + ( + "Preview", + { + "fields": ("get_preview",), + }, + ), ) def get_readonly_fields(self, *args, **kwargs): readonly_fields = super().get_readonly_fields(*args, **kwargs) allow_push_graphs_data_to_statsd = ( - not settings.ALLOW_PUSH_GRAPHS_DATA_TO_STATSD and - not settings.COLLECT_METRICS + not settings.ALLOW_PUSH_GRAPHS_DATA_TO_STATSD + and not settings.COLLECT_METRICS ) if allow_push_graphs_data_to_statsd: - readonly_fields.append('push_to_statsd') + readonly_fields.append("push_to_statsd") return readonly_fields def get_preview(self, obj): - return obj.render(name='preview') + return obj.render(name="preview") - get_preview.short_description = _('Graph') + get_preview.short_description = _("Graph") @register(Dashboard) class DashboardAdmin(RalphAdmin): - list_display = ['name', 'description', 'active', 'get_link'] + list_display = ["name", "description", "active", "get_link"] @mark_safe def get_link(self, obj): - return _('Dashboard'.format(reverse( - 'dashboard_view', args=(obj.pk,) - ))) - get_link.short_description = _('Link') + return _( + 'Dashboard'.format( + reverse("dashboard_view", args=(obj.pk,)) + ) + ) + + get_link.short_description = _("Link") diff --git a/src/ralph/dashboards/admin_filters.py b/src/ralph/dashboards/admin_filters.py index 60215fd394..055d44b9fa 100644 --- a/src/ralph/dashboards/admin_filters.py +++ b/src/ralph/dashboards/admin_filters.py @@ -8,20 +8,18 @@ class ByGraphFilter(admin.SimpleListFilter): - title = _('Graph ID') - parameter_name = 'graph-query' + title = _("Graph ID") + parameter_name = "graph-query" sep = GRAPH_QUERY_SEP - template = 'admin/filters/by-graph.html' + template = "admin/filters/by-graph.html" def lookups(self, request, model_admin): - return ( - ('', ''), - ) + return (("", ""),) def queryset(self, request, queryset): params = decode_params(self.value()) - graph_pk = params.get('pk') - filters = params.get('filters') + graph_pk = params.get("pk") + filters = params.get("filters") if graph_pk: graph = get_object_or_404(Graph, pk=graph_pk) queryset = graph.get_queryset_for_filter(queryset, filters) diff --git a/src/ralph/dashboards/api/routers.py b/src/ralph/dashboards/api/routers.py index cf51733b0c..c548563f81 100644 --- a/src/ralph/dashboards/api/routers.py +++ b/src/ralph/dashboards/api/routers.py @@ -1,6 +1,6 @@ from ralph.api import router from ralph.dashboards.api.views import GraphViewSet -router.register(r'graph', GraphViewSet) +router.register(r"graph", GraphViewSet) urlpatterns = [] diff --git a/src/ralph/dashboards/api/serializers.py b/src/ralph/dashboards/api/serializers.py index 43e3584f19..808e4d926b 100644 --- a/src/ralph/dashboards/api/serializers.py +++ b/src/ralph/dashboards/api/serializers.py @@ -5,7 +5,7 @@ class GraphSerializer(RalphAPISerializer): class Meta: model = Graph - fields = ('name', 'description', 'url') + fields = ("name", "description", "url") class GraphSerializerDetail(RalphAPISerializer): @@ -14,8 +14,8 @@ class Meta: def to_representation(self, instance): return { - 'name': instance.name, - 'description': instance.description, - 'params': instance.params, - 'data': instance.get_data(), + "name": instance.name, + "description": instance.description, + "params": instance.params, + "data": instance.get_data(), } diff --git a/src/ralph/dashboards/api/views.py b/src/ralph/dashboards/api/views.py index 63cdcca2c7..13de85e9c3 100644 --- a/src/ralph/dashboards/api/views.py +++ b/src/ralph/dashboards/api/views.py @@ -1,8 +1,5 @@ from rest_framework.viewsets import ReadOnlyModelViewSet -from ralph.dashboards.api.serializers import ( - GraphSerializer, - GraphSerializerDetail -) +from ralph.dashboards.api.serializers import GraphSerializer, GraphSerializerDetail from ralph.dashboards.models import Graph @@ -12,6 +9,6 @@ class GraphViewSet(ReadOnlyModelViewSet): detail_serializer_class = GraphSerializerDetail def get_serializer_class(self): - if self.action == 'retrieve': + if self.action == "retrieve": return self.detail_serializer_class return super().get_serializer_class() diff --git a/src/ralph/dashboards/filter_parser.py b/src/ralph/dashboards/filter_parser.py index e2f4f88c36..fd8bffab41 100644 --- a/src/ralph/dashboards/filter_parser.py +++ b/src/ralph/dashboards/filter_parser.py @@ -6,12 +6,11 @@ from dateutil.relativedelta import relativedelta from django.db.models import Q -FILTER_FROM_NOW = re.compile(r'([+-]?\d+)(\w)') +FILTER_FROM_NOW = re.compile(r"([+-]?\d+)(\w)") class FilterParser(object): - - or_sep = ',' + or_sep = "," def __init__(self, queryset, filters_dict, exclude_mode=False): self.filters = filters_dict @@ -24,11 +23,11 @@ def get_queryset(self): parsed_kwargs = {} parsed_args = [] for key, value in self.filters.items(): - params = key.split('|') + params = key.split("|") if len(params) == 1: parsed_kwargs[key] = value elif len(params) == 2: - filter_func = getattr(self, 'filter_' + params[1], None) + filter_func = getattr(self, "filter_" + params[1], None) if not filter_func: continue args, kwargs = filter_func(params[0], value) @@ -50,12 +49,12 @@ def filter_and(self, key, value): def filter_from_now(self, key, value): period_mapper = { - 'd': 'days', - 'm': 'months', - 'y': 'years', + "d": "days", + "m": "months", + "y": "years", } val, period = FILTER_FROM_NOW.match(value).groups() - result = datetime.date.today() + relativedelta(**{ - period_mapper.get(period): int(val) - }) - return [], {key: result.strftime('%Y-%m-%d')} + result = datetime.date.today() + relativedelta( + **{period_mapper.get(period): int(val)} + ) + return [], {key: result.strftime("%Y-%m-%d")} diff --git a/src/ralph/dashboards/helpers.py b/src/ralph/dashboards/helpers.py index 9b8fdbc41b..5107b027d5 100644 --- a/src/ralph/dashboards/helpers.py +++ b/src/ralph/dashboards/helpers.py @@ -23,9 +23,7 @@ def normalize_value(model_class, label, value): if isinstance(field, ChoiceField): choices = field.choice_class() try: - value = [ - i[0] for i in choices if i[1] == value - ].pop() + value = [i[0] for i in choices if i[1] == value].pop() except IndexError: # NOTE(romcheg): Choice not found for the filter value. # Leaving it as is. diff --git a/src/ralph/dashboards/management/commands/push_graphs_to_statsd.py b/src/ralph/dashboards/management/commands/push_graphs_to_statsd.py index 12019158ab..d9311593b4 100644 --- a/src/ralph/dashboards/management/commands/push_graphs_to_statsd.py +++ b/src/ralph/dashboards/management/commands/push_graphs_to_statsd.py @@ -14,11 +14,12 @@ def normalize(s): s = slugify(s) - return s.replace('-', '_') + return s.replace("-", "_") class Command(BaseCommand): """Push to statsd data generated by graphs.""" + help = textwrap.dedent(__doc__).strip() def handle(self, *args, **kwargs): @@ -27,6 +28,6 @@ def handle(self, *args, **kwargs): for graph in graphs: graph_data = graph.get_data() graph_name = normalize(graph.name) - for label, value in zip(graph_data['labels'], graph_data['series']): - path = '.'.join((graph_name, normalize(label))) + for label, value in zip(graph_data["labels"], graph_data["series"]): + path = ".".join((graph_name, normalize(label))) statsd.gauge(path, value) diff --git a/src/ralph/dashboards/migrations/0001_initial.py b/src/ralph/dashboards/migrations/0001_initial.py index 6d573eca2e..91cb042459 100644 --- a/src/ralph/dashboards/migrations/0001_initial.py +++ b/src/ralph/dashboards/migrations/0001_initial.py @@ -7,50 +7,117 @@ class Migration(migrations.Migration): - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), + ("contenttypes", "0002_remove_content_type_name"), ] operations = [ migrations.CreateModel( - name='Dashboard', + name="Dashboard", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('active', models.BooleanField(default=True)), - ('description', models.CharField(max_length=250, verbose_name='description', blank=True)), - ('interval', models.PositiveSmallIntegerField(default=60)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), + ( + "created", + models.DateTimeField( + auto_now_add=True, verbose_name="date created" + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ("active", models.BooleanField(default=True)), + ( + "description", + models.CharField( + max_length=250, verbose_name="description", blank=True + ), + ), + ("interval", models.PositiveSmallIntegerField(default=60)), ], options={ - 'abstract': False, - 'ordering': ['name'], + "abstract": False, + "ordering": ["name"], }, ), migrations.CreateModel( - name='Graph', + name="Graph", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('description', models.CharField(max_length=250, verbose_name='description', blank=True)), - ('aggregate_type', models.PositiveIntegerField(choices=[(1, 'Count'), (2, 'Max'), (3, 'Sum')])), - ('chart_type', models.PositiveIntegerField(choices=[(1, 'Verical Bar'), (2, 'Horizontal Bar'), (3, 'Pie Chart')])), - ('params', django_extensions.db.fields.json.JSONField(blank=True)), - ('active', models.BooleanField(default=True)), - ('model', models.ForeignKey(to='contenttypes.ContentType', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), + ( + "created", + models.DateTimeField( + auto_now_add=True, verbose_name="date created" + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "description", + models.CharField( + max_length=250, verbose_name="description", blank=True + ), + ), + ( + "aggregate_type", + models.PositiveIntegerField( + choices=[(1, "Count"), (2, "Max"), (3, "Sum")] + ), + ), + ( + "chart_type", + models.PositiveIntegerField( + choices=[ + (1, "Verical Bar"), + (2, "Horizontal Bar"), + (3, "Pie Chart"), + ] + ), + ), + ("params", django_extensions.db.fields.json.JSONField(blank=True)), + ("active", models.BooleanField(default=True)), + ( + "model", + models.ForeignKey( + to="contenttypes.ContentType", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, - 'ordering': ['name'], + "abstract": False, + "ordering": ["name"], }, ), migrations.AddField( - model_name='dashboard', - name='graphs', - field=models.ManyToManyField(to='dashboards.Graph', blank=True), + model_name="dashboard", + name="graphs", + field=models.ManyToManyField(to="dashboards.Graph", blank=True), ), ] diff --git a/src/ralph/dashboards/migrations/0002_auto_20170509_1404.py b/src/ralph/dashboards/migrations/0002_auto_20170509_1404.py index 906d0bd6db..3b6ff22664 100644 --- a/src/ralph/dashboards/migrations/0002_auto_20170509_1404.py +++ b/src/ralph/dashboards/migrations/0002_auto_20170509_1404.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('dashboards', '0001_initial'), + ("dashboards", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='graph', - name='aggregate_type', - field=models.PositiveIntegerField(choices=[(1, 'Count'), (2, 'Max'), (3, 'Sum'), (4, 'Ratio')]), + model_name="graph", + name="aggregate_type", + field=models.PositiveIntegerField( + choices=[(1, "Count"), (2, "Max"), (3, "Sum"), (4, "Ratio")] + ), ), ] diff --git a/src/ralph/dashboards/migrations/0003_graph_push_to_statsd.py b/src/ralph/dashboards/migrations/0003_graph_push_to_statsd.py index 20b22378c7..38b0463271 100644 --- a/src/ralph/dashboards/migrations/0003_graph_push_to_statsd.py +++ b/src/ralph/dashboards/migrations/0003_graph_push_to_statsd.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('dashboards', '0002_auto_20170509_1404'), + ("dashboards", "0002_auto_20170509_1404"), ] operations = [ migrations.AddField( - model_name='graph', - name='push_to_statsd', - field=models.BooleanField(default=False, help_text="Push graph's data to statsd."), + model_name="graph", + name="push_to_statsd", + field=models.BooleanField( + default=False, help_text="Push graph's data to statsd." + ), ), ] diff --git a/src/ralph/dashboards/migrations/0004_auto_20170926_1547.py b/src/ralph/dashboards/migrations/0004_auto_20170926_1547.py index 34c866b3c6..eecd6a0462 100644 --- a/src/ralph/dashboards/migrations/0004_auto_20170926_1547.py +++ b/src/ralph/dashboards/migrations/0004_auto_20170926_1547.py @@ -5,15 +5,22 @@ class Migration(migrations.Migration): - dependencies = [ - ('dashboards', '0003_graph_push_to_statsd'), + ("dashboards", "0003_graph_push_to_statsd"), ] operations = [ migrations.AlterField( - model_name='graph', - name='aggregate_type', - field=models.PositiveIntegerField(choices=[(1, 'Count'), (2, 'Count with zeros'), (3, 'Max'), (4, 'Sum'), (5, 'Ratio')]), + model_name="graph", + name="aggregate_type", + field=models.PositiveIntegerField( + choices=[ + (1, "Count"), + (2, "Count with zeros"), + (3, "Max"), + (4, "Sum"), + (5, "Ratio"), + ] + ), ), ] diff --git a/src/ralph/dashboards/migrations/0005_auto_20170927_1505.py b/src/ralph/dashboards/migrations/0005_auto_20170927_1505.py index 2ac41f7268..e2ae3cf1f5 100644 --- a/src/ralph/dashboards/migrations/0005_auto_20170927_1505.py +++ b/src/ralph/dashboards/migrations/0005_auto_20170927_1505.py @@ -5,15 +5,23 @@ class Migration(migrations.Migration): - dependencies = [ - ('dashboards', '0004_auto_20170926_1547'), + ("dashboards", "0004_auto_20170926_1547"), ] operations = [ migrations.AlterField( - model_name='graph', - name='aggregate_type', - field=models.PositiveIntegerField(choices=[(1, 'Count'), (2, 'Count with zeros'), (3, 'Max'), (4, 'Sum'), (5, 'Sum boolean values'), (6, 'Ratio')]), + model_name="graph", + name="aggregate_type", + field=models.PositiveIntegerField( + choices=[ + (1, "Count"), + (2, "Count with zeros"), + (3, "Max"), + (4, "Sum"), + (5, "Sum boolean values"), + (6, "Ratio"), + ] + ), ), ] diff --git a/src/ralph/dashboards/migrations/0006_auto_20171221_0959.py b/src/ralph/dashboards/migrations/0006_auto_20171221_0959.py index 940db304e7..fbe9346f55 100644 --- a/src/ralph/dashboards/migrations/0006_auto_20171221_0959.py +++ b/src/ralph/dashboards/migrations/0006_auto_20171221_0959.py @@ -5,20 +5,32 @@ class Migration(migrations.Migration): - dependencies = [ - ('dashboards', '0005_auto_20170927_1505'), + ("dashboards", "0005_auto_20170927_1505"), ] operations = [ migrations.AlterField( - model_name='graph', - name='aggregate_type', - field=models.PositiveIntegerField(choices=[(1, 'Count'), (2, 'Count with zeros'), (3, 'Max'), (4, 'Sum'), (5, 'Sum with zeros'), (6, 'Sum boolean values'), (7, 'Sum negated boolean values'), (8, 'Ratio')]), + model_name="graph", + name="aggregate_type", + field=models.PositiveIntegerField( + choices=[ + (1, "Count"), + (2, "Count with zeros"), + (3, "Max"), + (4, "Sum"), + (5, "Sum with zeros"), + (6, "Sum boolean values"), + (7, "Sum negated boolean values"), + (8, "Ratio"), + ] + ), ), migrations.AlterField( - model_name='graph', - name='chart_type', - field=models.PositiveIntegerField(choices=[(1, 'Vertical Bar'), (2, 'Horizontal Bar'), (3, 'Pie Chart')]), + model_name="graph", + name="chart_type", + field=models.PositiveIntegerField( + choices=[(1, "Vertical Bar"), (2, "Horizontal Bar"), (3, "Pie Chart")] + ), ), ] diff --git a/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py b/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py index f3366c3788..5f0dcc293a 100644 --- a/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py +++ b/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py @@ -8,21 +8,19 @@ def clear_sitetree_cache(apps, schema_editor): try: - cache = caches['default'] + cache = caches["default"] cache.delete("sitetrees") - except Exception as e: + except Exception: pass class Migration(migrations.Migration): - dependencies = [ - ('dashboards', '0006_auto_20171221_0959'), + ("dashboards", "0006_auto_20171221_0959"), ] operations = [ migrations.RunPython( - code=clear_sitetree_cache, - reverse_code=clear_sitetree_cache + code=clear_sitetree_cache, reverse_code=clear_sitetree_cache ) ] diff --git a/src/ralph/dashboards/models.py b/src/ralph/dashboards/models.py index 790fa54291..46c2a7cc20 100644 --- a/src/ralph/dashboards/models.py +++ b/src/ralph/dashboards/models.py @@ -9,18 +9,14 @@ from ralph.dashboards.filter_parser import FilterParser from ralph.dashboards.renderers import HorizontalBar, PieChart, VerticalBar -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin def _unpack_series(series): if not isinstance(series, str): - raise ValueError('Series should be string') - series_field, fn = _to_pair(series, '|') - if (series_field != fn) and (fn != 'distinct'): + raise ValueError("Series should be string") + series_field, fn = _to_pair(series, "|") + if (series_field != fn) and (fn != "distinct"): raise ValueError( "Series supports Only `distinct` (you put '{}')".format(fn) # noqa ) @@ -29,43 +25,40 @@ def _unpack_series(series): return series_field, fn -class Dashboard( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model -): +class Dashboard(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): active = models.BooleanField(default=True) - description = models.CharField('description', max_length=250, blank=True) - graphs = models.ManyToManyField('Graph', blank=True) + description = models.CharField("description", max_length=250, blank=True) + graphs = models.ManyToManyField("Graph", blank=True) interval = models.PositiveSmallIntegerField(default=60) def ratio_handler(aggregate_func, series, aggregate_expression): if not isinstance(series, list): - raise ValueError('Ratio aggregation requires series to be list') + raise ValueError("Ratio aggregation requires series to be list") if len(series) != 2: - raise ValueError( - 'Ratio aggregation requires series to be list of size 2' - ) + raise ValueError("Ratio aggregation requires series to be list of size 2") # postgres does not support Sum with boolean field so we need to use # Case-When with integer values here return ( - Sum(Case( - When(Q(**{series[0]: True}), then=Value(1)), - When(Q(**{series[0]: False}), then=Value(0)), - default=Value(0), - output_field=IntegerField() - )) * 100.0 / Count(series[1]) + Sum( + Case( + When(Q(**{series[0]: True}), then=Value(1)), + When(Q(**{series[0]: False}), then=Value(0)), + default=Value(0), + output_field=IntegerField(), + ) + ) + * 100.0 + / Count(series[1]) ) def zero_handler(aggregate_func, series, aggregate_expression): series_field, _ = _unpack_series(series) - return ( - Coalesce( - aggregate_func(aggregate_expression or series_field), Value(0), - output_field=IntegerField()) + return Coalesce( + aggregate_func(aggregate_expression or series_field), + Value(0), + output_field=IntegerField(), ) @@ -86,45 +79,44 @@ def sum_bool_value_handler( for key, value in mapping.items() ], default=Value(default_value), - output_field=IntegerField() + output_field=IntegerField(), ) ) class AggregateType(Choices): _ = Choices.Choice - aggregate_count = _('Count').extra(aggregate_func=Count) - aggregate_count_with_zeros = _('Count with zeros').extra( + aggregate_count = _("Count").extra(aggregate_func=Count) + aggregate_count_with_zeros = _("Count with zeros").extra( aggregate_func=Count, handler=zero_handler ) - aggregate_max = _('Max').extra(aggregate_func=Max) - aggregate_sum = _('Sum').extra(aggregate_func=Sum) - aggregate_sum_with_zeros = _('Sum with zeros').extra( + aggregate_max = _("Max").extra(aggregate_func=Max) + aggregate_sum = _("Sum").extra(aggregate_func=Sum) + aggregate_sum_with_zeros = _("Sum with zeros").extra( aggregate_func=Sum, handler=zero_handler ) - aggregate_sum_bool_values = _('Sum boolean values').extra( + aggregate_sum_bool_values = _("Sum boolean values").extra( aggregate_func=Sum, handler=sum_bool_value_handler ) - aggregate_sum_bool_negated_values = _('Sum negated boolean values').extra( - aggregate_func=Sum, handler=partial( + aggregate_sum_bool_negated_values = _("Sum negated boolean values").extra( + aggregate_func=Sum, + handler=partial( sum_bool_value_handler, mapping={ False: 1, True: 0, }, - ) - ) - aggregate_ratio = _('Ratio').extra( - aggregate_func=Count, handler=ratio_handler + ), ) + aggregate_ratio = _("Ratio").extra(aggregate_func=Count, handler=ratio_handler) class ChartType(Choices): # NOTE: append new type _ = Choices.Choice - vertical_bar = _('Vertical Bar').extra(renderer=VerticalBar) - horizontal_bar = _('Horizontal Bar').extra(renderer=HorizontalBar) - pie_chart = _('Pie Chart').extra(renderer=PieChart) + vertical_bar = _("Vertical Bar").extra(renderer=VerticalBar) + horizontal_bar = _("Horizontal Bar").extra(renderer=HorizontalBar) + pie_chart = _("Pie Chart").extra(renderer=PieChart) def _to_pair(text, sep): @@ -142,9 +134,10 @@ class GroupingLabel: """ Adds grouping-by-year feature to query based on `label_group` """ - sep = '|' - date_fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] - date_format = ('%Y-', '%m', '-%d', ' %H:', '%i', ':%s') + + sep = "|" + date_fields = ["year", "month", "day", "hour", "minute", "second"] + date_format = ("%Y-", "%m", "-%d", " %H:", "%i", ":%s") def __init__(self, connection, label_group): self.connection = connection @@ -158,42 +151,41 @@ def has_group(self): return self.orig_label != self.label def _group_by_part_of_date(self, date_part): - field_name = self.orig_label.split('__')[-1] + field_name = self.orig_label.split("__")[-1] return self.connection.ops.date_trunc_sql(date_part, field_name) def apply_grouping(self, queryset): if self.has_group: if self.label in self.date_fields: - queryset = queryset.extra({ - self.label: self._group_by_part_of_date(self.label) - }) + queryset = queryset.extra( + {self.label: self._group_by_part_of_date(self.label)} + ) else: - queryset = queryset.extra({ - self.label: getattr(self, 'group_' + self.label)() - }) + queryset = queryset.extra( + {self.label: getattr(self, "group_" + self.label)()} + ) return queryset def _format_part_of_date(self, value): i = self.date_fields.index(self.label) + 1 - format_str = ''.join([f for f in self.date_format[:i]]) + format_str = "".join([f for f in self.date_format[:i]]) return value.strftime(format_str) def format_label(self, value): if self.has_group: - value = self._format_part_of_date(value).strip('-').strip(':') + value = self._format_part_of_date(value).strip("-").strip(":") return str(value) class Graph(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): - description = models.CharField('description', max_length=250, blank=True) + description = models.CharField("description", max_length=250, blank=True) model = models.ForeignKey(ContentType, on_delete=models.CASCADE) aggregate_type = models.PositiveIntegerField(choices=AggregateType()) chart_type = models.PositiveIntegerField(choices=ChartType()) params = JSONField(blank=True) active = models.BooleanField(default=True) push_to_statsd = models.BooleanField( - default=False, - help_text='Push graph\'s data to statsd.' + default=False, help_text="Push graph's data to statsd." ) @property @@ -202,43 +194,39 @@ def changelist_model(self): @property def custom_changelist_model(self): - model_name_from_params = ( - self.params.get('target') and self.params['target'].get('model') - ) + model_name_from_params = self.params.get("target") and self.params[ + "target" + ].get("model") if not model_name_from_params: return None try: - return ContentType.objects.get( - model=model_name_from_params.lower() - ) + return ContentType.objects.get(model=model_name_from_params.lower()) except ContentType.DoesNotExist: raise ValueError( 'Model "{}" does not exist.' - 'Please provide correct model to target.model'.format( + "Please provide correct model to target.model".format( model_name_from_params ) ) @property def custom_changelist_filter_key(self): - return ( - self.params.get('target') and self.params['target'].get('filter') - ) + return self.params.get("target") and self.params["target"].get("filter") @property def changelist_filter_key(self): - return self.custom_changelist_filter_key or self.params['labels'] + return self.custom_changelist_filter_key or self.params["labels"] def pop_annotate_filters(self, filters): annotate_filters = {} for key in list(filters.keys()): - if key.startswith('series'): + if key.startswith("series"): annotate_filters.update({key: filters.pop(key)}) return annotate_filters def apply_parital_filtering(self, queryset): - filters = self.params.get('filters', None) - excludes = self.params.get('excludes', None) + filters = self.params.get("filters", None) + excludes = self.params.get("excludes", None) if filters: queryset = FilterParser(queryset, filters).get_queryset() if excludes: @@ -249,16 +237,16 @@ def apply_parital_filtering(self, queryset): @property def has_grouping(self): - labels = self.params.get('labels', '') + labels = self.params.get("labels", "") grouping_label = GroupingLabel(connection, labels) return grouping_label.has_group def apply_limit(self, queryset): - limit = self.params.get('limit', None) + limit = self.params.get("limit", None) return queryset[:limit] def apply_sort(self, queryset): - order = self.params.get('sort', None) + order = self.params.get("sort", None) if order: return queryset.order_by(order) return queryset @@ -267,11 +255,9 @@ def get_aggregation(self): aggregate_type = AggregateType.from_id(self.aggregate_type) aggregate_func = aggregate_type.aggregate_func # aggregate choice might have defined custom handler - handler = getattr( - aggregate_type, 'handler', self._default_aggregation_handler - ) - series = self.params.get('series', '') - aggregate_expression = self.params.get('aggregate_expression') + handler = getattr(aggregate_type, "handler", self._default_aggregation_handler) + series = self.params.get("series", "") + aggregate_expression = self.params.get("aggregate_expression") return handler( aggregate_func=aggregate_func, series=series, @@ -292,27 +278,22 @@ def _default_aggregation_handler( ) ) - aggregate_fn_kwargs['distinct'] = True + aggregate_fn_kwargs["distinct"] = True return aggregate_func( - aggregate_expression or series_field, - **aggregate_fn_kwargs + aggregate_expression or series_field, **aggregate_fn_kwargs ) def build_queryset(self, annotated=True, queryset=None): queryset = queryset or self.model.model_class().objects.all() - grouping_label = GroupingLabel(connection, self.params['labels']) + grouping_label = GroupingLabel(connection, self.params["labels"]) if annotated: queryset = grouping_label.apply_grouping(queryset) # pop filters which are applied on annotated queryset - annotate_filters = self.pop_annotate_filters( - self.params.get('filters', {}) - ) + annotate_filters = self.pop_annotate_filters(self.params.get("filters", {})) queryset = self.apply_parital_filtering(queryset) if annotated: - queryset = queryset.values( - grouping_label.label - ).annotate( + queryset = queryset.values(grouping_label.label).annotate( series=self.get_aggregation(), ) if annotate_filters: @@ -324,38 +305,39 @@ def build_queryset(self, annotated=True, queryset=None): def get_data(self): queryset = self.build_queryset() - grouping_label = GroupingLabel(connection, self.params['labels']) + grouping_label = GroupingLabel(connection, self.params["labels"]) label = grouping_label.label return { - 'labels': [ - grouping_label.format_label(q[label]) for q in queryset - ], - 'series': [int(q['series']) for q in queryset], + "labels": [grouping_label.format_label(q[label]) for q in queryset], + "series": [int(q["series"]) for q in queryset], } def render(self, **context): chart_type = ChartType.from_id(self.chart_type) - renderer = getattr(chart_type, 'renderer', None) + renderer = getattr(chart_type, "renderer", None) if not renderer: - raise RuntimeError('Wrong renderer.') + raise RuntimeError("Wrong renderer.") return renderer(self).render(context) def get_queryset_for_filter(self, queryset, filters): filter_key = self.changelist_filter_key if self.custom_changelist_model: - value_param = self.params['target'].get('value', 'id') - values = self.build_queryset(annotated=False).filter( - **filters - ).distinct().values_list(value_param, flat=True) + value_param = self.params["target"].get("value", "id") + values = ( + self.build_queryset(annotated=False) + .filter(**filters) + .distinct() + .values_list(value_param, flat=True) + ) queryset = queryset.filter(**{filter_key: values}) # apply additional filters on changelist # useful when you use specific aggregation (ex. sum boolean values) # and you need to inject it to filters (ex. to filter objects # having some field set to false) when switching model in # changelist - queryset = queryset.filter(**self.params['target'].get( - 'additional_filters', {} - )) + queryset = queryset.filter( + **self.params["target"].get("additional_filters", {}) + ) else: queryset = self.build_queryset(annotated=False, queryset=queryset) if filters: diff --git a/src/ralph/dashboards/renderers.py b/src/ralph/dashboards/renderers.py index a01537caa7..0538d6507d 100644 --- a/src/ralph/dashboards/renderers.py +++ b/src/ralph/dashboards/renderers.py @@ -10,7 +10,7 @@ from ralph.dashboards.helpers import encode_params, normalize_value logger = logging.getLogger(__name__) -GRAPH_QUERY_SEP = '|' +GRAPH_QUERY_SEP = "|" def build_filters(labels, value): @@ -19,37 +19,38 @@ def build_filters(labels, value): return {params[0]: value} if len(params) == 2: field, aggr = params - if aggr == 'year': + if aggr == "year": return { - '{}__gte'.format(field): '{}-01-01'.format(value), - '{}__lte'.format(field): '{}-12-31'.format(value), + "{}__gte".format(field): "{}-01-01".format(value), + "{}__lte".format(field): "{}-12-31".format(value), } - if aggr == 'month': - year, month = value.split('-') + if aggr == "month": + year, month = value.split("-") days_in_month = calendar.monthrange(int(year), int(month))[1] return { - '{}__gte'.format(field): '{}-01'.format(value), - '{}__lte'.format(field): '{}-{}'.format(value, days_in_month), + "{}__gte".format(field): "{}-01".format(value), + "{}__lte".format(field): "{}-{}".format(value, days_in_month), } - if aggr == 'day': + if aggr == "day": return { - '{}__gte'.format(field): '{} 00:00:00'.format(value), - '{}__lte'.format(field): '{} 23:59:59'.format(value), + "{}__gte".format(field): "{} 00:00:00".format(value), + "{}__lte".format(field): "{} 23:59:59".format(value), } return {} class ChartistGraphRenderer(object): """Renderer for Chartist.js.""" + func = None options = None - template_name = 'dashboard/templatetags/chartist_render_graph.html' + template_name = "dashboard/templatetags/chartist_render_graph.html" _default_options = { - 'distributeSeries': False, - 'chartPadding': 20, - 'height': '350px' + "distributeSeries": False, + "chartPadding": 20, + "height": "350px", } - plugins = {'ctBarLabels': {}} + plugins = {"ctBarLabels": {}} graph_query_sep = GRAPH_QUERY_SEP def __init__(self, obj): @@ -57,12 +58,12 @@ def __init__(self, obj): def get_func(self): if not self.func: - raise NotImplementedError('Specify func attr.') + raise NotImplementedError("Specify func attr.") return self.func def get_template_name(self): if not self.template_name: - raise NotImplementedError('Specify template_name attr.') + raise NotImplementedError("Specify template_name attr.") return self.template_name def get_options(self, data=None): @@ -73,30 +74,32 @@ def get_options(self, data=None): def _labels2urls(self, model, graph_id, values): meta = model._meta - base_url = reverse( - "admin:%s_%s_changelist" % ( - meta.app_label, meta.model_name - ) - ) + base_url = reverse("admin:%s_%s_changelist" % (meta.app_label, meta.model_name)) urls = [] for value in values: - labels = self.obj.params['labels'] - url = '?'.join([ - base_url, - urlencode({ - 'graph-query': encode_params({ - 'pk': graph_id, - 'filters': build_filters( - labels=labels, - value=normalize_value( - label=labels.split(GRAPH_QUERY_SEP)[0], - model_class=self.obj.model.model_class(), - value=value, + labels = self.obj.params["labels"] + url = "?".join( + [ + base_url, + urlencode( + { + "graph-query": encode_params( + { + "pk": graph_id, + "filters": build_filters( + labels=labels, + value=normalize_value( + label=labels.split(GRAPH_QUERY_SEP)[0], + model_class=self.obj.model.model_class(), + value=value, + ), + ), + } ) - ), - }) - }), - ]) + } + ), + ] + ) urls.append(url) return urls @@ -104,22 +107,22 @@ def _labels2urls(self, model, graph_id, values): def _series_with_urls(self, series, urls): series_with_urls = [] for value, url in zip(series, urls): - series_with_urls.append({ - 'value': value, - 'meta': { - 'clickUrl': url, + series_with_urls.append( + { + "value": value, + "meta": { + "clickUrl": url, + }, } - }) + ) return series_with_urls def post_data_hook(self, data): try: click_urls = self._labels2urls( - self.obj.changelist_model, self.obj.id, data['labels'] - ) - data['series'] = self._series_with_urls( - data['series'], click_urls + self.obj.changelist_model, self.obj.id, data["labels"] ) + data["series"] = self._series_with_urls(data["series"], click_urls) except NoReverseMatch as e: # graph will be non-clickable when model is not exposed in # admin @@ -138,60 +141,62 @@ def render(self, context): error = str(e) finally: options = self.get_options(data) - context.update({ - 'error': error, - 'graph': self.obj, - 'options': json.dumps(options), - 'options_raw': options, - 'func': self.func, - 'plugins': self.plugins, - }) + context.update( + { + "error": error, + "graph": self.obj, + "options": json.dumps(options), + "options_raw": options, + "func": self.func, + "plugins": self.plugins, + } + ) context.update(**data) return mark_safe(render_to_string(self.get_template_name(), context)) class HorizontalBar(ChartistGraphRenderer): - func = 'Bar' + func = "Bar" options = { - 'horizontalBars': True, - 'axisY': { - 'offset': 70, + "horizontalBars": True, + "axisY": { + "offset": 70, + }, + "axisX": { + "onlyInteger": True, }, - 'axisX': { - 'onlyInteger': True, - } } class VerticalBar(ChartistGraphRenderer): - func = 'Bar' + func = "Bar" options = { - 'axisY': { - 'onlyInteger': True, + "axisY": { + "onlyInteger": True, } } class PieChart(ChartistGraphRenderer): - func = 'Pie' + func = "Pie" _default_options = { - 'distributeSeries': True, + "distributeSeries": True, } options = { - 'donut': True, + "donut": True, } def get_options(self, data): - series = data.get('series') + series = data.get("series") if series: - self.options['total'] = sum(s['value'] for s in series) + self.options["total"] = sum(s["value"] for s in series) return super().get_options(data) def include_values_in_labels(self, data): - for idx, pack in enumerate(zip(data['labels'], data['series'])): + for idx, pack in enumerate(zip(data["labels"], data["series"])): label, series = pack - new_label = "{} ({})".format(label, series['value']) - data['labels'][idx] = new_label + new_label = "{} ({})".format(label, series["value"]) + data["labels"][idx] = new_label return data def post_data_hook(self, data): diff --git a/src/ralph/dashboards/templatetags/graph_tags.py b/src/ralph/dashboards/templatetags/graph_tags.py index 05527f5d52..4e5edab7a9 100644 --- a/src/ralph/dashboards/templatetags/graph_tags.py +++ b/src/ralph/dashboards/templatetags/graph_tags.py @@ -4,6 +4,6 @@ register = Library() -@register.inclusion_tag('dashboard/templatetags/render_graph.html') +@register.inclusion_tag("dashboard/templatetags/render_graph.html") def render_graph(graph): - return {'graph': graph} + return {"graph": graph} diff --git a/src/ralph/dashboards/tests/factories.py b/src/ralph/dashboards/tests/factories.py index bb3a5aafb2..cb15f4c620 100644 --- a/src/ralph/dashboards/tests/factories.py +++ b/src/ralph/dashboards/tests/factories.py @@ -8,8 +8,7 @@ class DashboardFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'dashboard {}'.format(n)) + name = factory.Sequence(lambda n: "dashboard {}".format(n)) class Meta: model = Dashboard @@ -20,18 +19,19 @@ def data_center_content_type(): class GraphFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'graph {}'.format(n)) + name = factory.Sequence(lambda n: "graph {}".format(n)) # model is ContentType and should be lazy evaluated until it's populated model = factory.LazyFunction(data_center_content_type) - aggregate_type = factory.Iterator([ - AggregateType.aggregate_max.id, AggregateType.aggregate_count.id, - AggregateType.aggregate_sum.id - ]) - chart_type = factory.Iterator([ - ChartType.vertical_bar.id, ChartType.horizontal_bar.id, - ChartType.pie_chart.id - ]) + aggregate_type = factory.Iterator( + [ + AggregateType.aggregate_max.id, + AggregateType.aggregate_count.id, + AggregateType.aggregate_sum.id, + ] + ) + chart_type = factory.Iterator( + [ChartType.vertical_bar.id, ChartType.horizontal_bar.id, ChartType.pie_chart.id] + ) class Meta: model = Graph diff --git a/src/ralph/dashboards/tests/test_api.py b/src/ralph/dashboards/tests/test_api.py index 6ff05ef3eb..6f07510a10 100644 --- a/src/ralph/dashboards/tests/test_api.py +++ b/src/ralph/dashboards/tests/test_api.py @@ -10,18 +10,18 @@ def test_endpoint_should_return_get_data_and_params(self): graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, params={ - 'series': 'id', - 'labels': 'hostname', - } + "series": "id", + "labels": "hostname", + }, ) - url = reverse('graph-detail', args=(graph.id,)) + url = reverse("graph-detail", args=(graph.id,)) response = self.client.get(url) self.assertEqual( response.data, { - 'name': graph.name, - 'description': graph.description, - 'data': graph.get_data(), - 'params': graph.params - } + "name": graph.name, + "description": graph.description, + "data": graph.get_data(), + "params": graph.params, + }, ) diff --git a/src/ralph/dashboards/tests/test_models.py b/src/ralph/dashboards/tests/test_models.py index a8fa9107e9..60fdcc3bee 100644 --- a/src/ralph/dashboards/tests/test_models.py +++ b/src/ralph/dashboards/tests/test_models.py @@ -13,117 +13,132 @@ class GraphQuerysetForFilterTestCase(TestCase): def test_filtering_queryset(self): DataCenterAssetFullFactory.create_batch( - 2, service_env__service__name='ServiceA', + 2, + service_env__service__name="ServiceA", ) DataCenterAssetFullFactory.create_batch( - 1, service_env__service__name='ServiceB', + 1, + service_env__service__name="ServiceB", ) DataCenterAssetFullFactory.create_batch( - 3, service_env__service__name='ServiceC', + 3, + service_env__service__name="ServiceC", ) - ServiceEnvironmentFactory.create(service__name='ServiceD') + ServiceEnvironmentFactory.create(service__name="ServiceD") graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, params={ - 'series': 'id', - 'labels': 'service_env__service__name', + "series": "id", + "labels": "service_env__service__name", }, ) dca_qs = DataCenterAsset.objects.all() - filtered_qs = graph.get_queryset_for_filter(dca_qs, { - 'service_env__service__name': 'ServiceA', - }) + filtered_qs = graph.get_queryset_for_filter( + dca_qs, + { + "service_env__service__name": "ServiceA", + }, + ) self.assertEqual(filtered_qs.count(), 2) self.assertEqual( - list(filtered_qs.values_list('service_env__service__name', flat=True)), - ['ServiceA', 'ServiceA'] + list(filtered_qs.values_list("service_env__service__name", flat=True)), + ["ServiceA", "ServiceA"], ) def test_filtering_queryset_with_target_model(self): DataCenterAssetFullFactory.create_batch( - 2, service_env__service__name='ServiceA', + 2, + service_env__service__name="ServiceA", ) DataCenterAssetFullFactory.create_batch( - 1, service_env__service__name='ServiceB', + 1, + service_env__service__name="ServiceB", ) DataCenterAssetFullFactory.create_batch( - 3, service_env__service__name='ServiceC', + 3, + service_env__service__name="ServiceC", ) - ServiceEnvironmentFactory.create(service__name='ServiceD') + ServiceEnvironmentFactory.create(service__name="ServiceD") graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, params={ - 'series': 'id', - 'labels': 'service__name', - 'target': { - 'model': 'DataCenterAsset', - 'filter': 'service_env__service__name__in', - 'value': 'service__name', - } + "series": "id", + "labels": "service__name", + "target": { + "model": "DataCenterAsset", + "filter": "service_env__service__name__in", + "value": "service__name", + }, }, ) graph.model = ContentType.objects.get_for_model(ServiceEnvironment) graph.save() dca_qs = DataCenterAsset.objects.all() - filtered_qs = graph.get_queryset_for_filter(dca_qs, { - 'service__name': 'ServiceA', - }) + filtered_qs = graph.get_queryset_for_filter( + dca_qs, + { + "service__name": "ServiceA", + }, + ) self.assertEqual(filtered_qs.count(), 2) self.assertEqual( - list(filtered_qs.values_list('service_env__service__name', flat=True)), - ['ServiceA', 'ServiceA'] + list(filtered_qs.values_list("service_env__service__name", flat=True)), + ["ServiceA", "ServiceA"], ) def test_filtering_queryset_with_additional_filters(self): - service_env_a = ServiceEnvironmentFactory(service__name='ServiceA') + service_env_a = ServiceEnvironmentFactory(service__name="ServiceA") DataCenterAssetFullFactory.create_batch( 2, service_env=service_env_a, scmstatuscheck=None ) DataCenterAssetFullFactory.create_batch( - 3, service_env=service_env_a, - scmstatuscheck__check_result=SCMCheckResult.scm_error + 3, + service_env=service_env_a, + scmstatuscheck__check_result=SCMCheckResult.scm_error, ) DataCenterAssetFullFactory.create_batch( 4, service_env=service_env_a, scmstatuscheck__ok=True ) DataCenterAssetFullFactory.create_batch( - 1, service_env__service__name='ServiceB', + 1, + service_env__service__name="ServiceB", ) DataCenterAssetFullFactory.create_batch( - 3, service_env__service__name='ServiceC', + 3, + service_env__service__name="ServiceC", ) - ServiceEnvironmentFactory.create(service__name='ServiceD') + ServiceEnvironmentFactory.create(service__name="ServiceD") graph = GraphFactory( aggregate_type=AggregateType.aggregate_sum_bool_negated_values.id, params={ - 'series': 'id', - 'labels': 'service__name', - 'target': { - 'model': 'DataCenterAsset', - 'filter': 'service_env__service__name__in', - 'value': 'service__name', - 'additional_filters': { - 'scmstatuscheck__ok': False - }, - } + "series": "id", + "labels": "service__name", + "target": { + "model": "DataCenterAsset", + "filter": "service_env__service__name__in", + "value": "service__name", + "additional_filters": {"scmstatuscheck__ok": False}, + }, }, model=ContentType.objects.get_for_model(ServiceEnvironment), ) dca_qs = DataCenterAsset.objects.all() - filtered_qs = graph.get_queryset_for_filter(dca_qs, { - 'service__name': 'ServiceA' - }) + filtered_qs = graph.get_queryset_for_filter( + dca_qs, {"service__name": "ServiceA"} + ) self.assertEqual(filtered_qs.count(), 3) self.assertEqual( - list(filtered_qs.values_list( - 'service_env__service__name', 'scmstatuscheck__ok' - )), - [('ServiceA', False)] * 3 + list( + filtered_qs.values_list( + "service_env__service__name", "scmstatuscheck__ok" + ) + ), + [("ServiceA", False)] * 3, ) diff --git a/src/ralph/dashboards/tests/test_parser.py b/src/ralph/dashboards/tests/test_parser.py index 61e5a31e6f..6fa9328322 100644 --- a/src/ralph/dashboards/tests/test_parser.py +++ b/src/ralph/dashboards/tests/test_parser.py @@ -19,13 +19,10 @@ from ralph.data_center.models import DataCenterAsset from ralph.data_center.tests.factories import ( DataCenterAssetFactory, - DataCenterAssetFullFactory + DataCenterAssetFullFactory, ) from ralph.security.models import Vulnerability -from ralph.security.tests.factories import ( - SecurityScanFactory, - VulnerabilityFactory -) +from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory from ralph.tests.models import Bar ARGS, KWARGS = (0, 1) @@ -38,37 +35,35 @@ def setUp(self): @unpack @data( - ('2y', relativedelta(years=2)), - ('-2y', relativedelta(years=-2)), - ('9m', relativedelta(months=9)), - ('-9m', relativedelta(months=-9)), - ('55d', relativedelta(days=55)), - ('-55d', relativedelta(days=-55)), + ("2y", relativedelta(years=2)), + ("-2y", relativedelta(years=-2)), + ("9m", relativedelta(months=9)), + ("-9m", relativedelta(months=-9)), + ("55d", relativedelta(days=55)), + ("-55d", relativedelta(days=-55)), ) def test_filter_from_now(self, filter_str, expect): - key = 'foo' + key = "foo" result = self.parser.filter_from_now(key, filter_str) pp = datetime.date.today() + expect - self.assertEqual( - result[KWARGS], {key: pp.strftime('%Y-%m-%d')} - ) + self.assertEqual(result[KWARGS], {key: pp.strftime("%Y-%m-%d")}) @unpack @data( - ('1', Q(key='1')), - ('1,2', Q(key='1') | Q(key='2')), + ("1", Q(key="1")), + ("1,2", Q(key="1") | Q(key="2")), ) def test_process_value(self, value, expect): - result = self.parser.filter_or('key', value) + result = self.parser.filter_or("key", value) self.assertEqual(str(result[ARGS][0]), str(expect)) @unpack @data( - (['1'], Q(key='1')), - (['1', '2'], Q(key='1') & Q(key='2')), + (["1"], Q(key="1")), + (["1", "2"], Q(key="1") & Q(key="2")), ) def test_process_value_as_list(self, value, expect): - result = self.parser.filter_and('key', value) + result = self.parser.filter_and("key", value) self.assertEqual(str(result[ARGS][0]), str(expect)) @@ -77,12 +72,10 @@ class GraphModelTest(TestCase): @unpack @data( ({}, 0), - ({'series__lte': 3}, 1), - ({'series__lte': 5, 'series__qte': 3}, 2), + ({"series__lte": 3}, 1), + ({"series__lte": 5, "series__qte": 3}, 2), ) - def test_annotate_fitler_should_pop_from_filters( - self, orig_filters, length - ): + def test_annotate_fitler_should_pop_from_filters(self, orig_filters, length): graph = Graph() filters = copy.deepcopy(orig_filters) result = graph.pop_annotate_filters(filters) @@ -93,7 +86,7 @@ def test_get_data_for_choices_field_returns_names(self): test_data = { SCMCheckResult.scm_ok: 3, SCMCheckResult.check_failed: 2, - SCMCheckResult.scm_error: 1 + SCMCheckResult.scm_error: 1, } data_center_assets = DataCenterAssetFullFactory.create_batch( @@ -107,7 +100,7 @@ def test_get_data_for_choices_field_returns_names(self): scm_checks.append( SCMStatusCheckFactory( check_result=check_result, - base_object=data_center_assets[dca_number] + base_object=data_center_assets[dca_number], ) ) dca_number += 1 @@ -118,35 +111,30 @@ def test_get_data_for_choices_field_returns_names(self): "filters": {}, "labels": "scmstatuscheck__check_result", "series": "id", - "sort": "series" + "sort": "series", } ) ) for check_result in test_data: - encoded_params = encode_params({ - 'pk': graph.pk, - 'filters': {'scmstatuscheck__check_result': check_result.id} - }) + encoded_params = encode_params( + { + "pk": graph.pk, + "filters": {"scmstatuscheck__check_result": check_result.id}, + } + ) graph_filter = ByGraphFilter( - None, - {'graph-query': encoded_params}, - DataCenterAsset, - DataCenterAdmin + None, {"graph-query": encoded_params}, DataCenterAsset, DataCenterAdmin ) qs = graph_filter.queryset(None, DataCenterAsset.objects.all()) self.assertEqual(len(qs), test_data[check_result]) - encoded_params = encode_params({ - 'pk': graph.pk, - 'filters': {'scmstatuscheck__check_result': None} - }) + encoded_params = encode_params( + {"pk": graph.pk, "filters": {"scmstatuscheck__check_result": None}} + ) graph_filter = ByGraphFilter( - None, - {'graph-query': encoded_params}, - DataCenterAsset, - DataCenterAdmin + None, {"graph-query": encoded_params}, DataCenterAsset, DataCenterAdmin ) qs = graph_filter.queryset(None, DataCenterAsset.objects.all()) @@ -154,19 +142,17 @@ def test_get_data_for_choices_field_returns_names(self): def _get_graph_params(self, update): data = { - 'filters': {}, - 'labels': 'barcode', - 'series': 'price', + "filters": {}, + "labels": "barcode", + "series": "price", } data.update(update) return data def test_key_limit_limits_records_when_present(self): limit = 5 - self.data_center_assets = DataCenterAssetFullFactory.create_batch( - 2 * limit - ) - graph = GraphFactory(params=self._get_graph_params({'limit': limit})) + self.data_center_assets = DataCenterAssetFullFactory.create_batch(2 * limit) + graph = GraphFactory(params=self._get_graph_params({"limit": limit})) qs = graph.build_queryset() @@ -174,81 +160,86 @@ def test_key_limit_limits_records_when_present(self): def test_key_sort_sorts_records_ascending_when_present(self): self.data_center_assets = DataCenterAssetFullFactory.create_batch(10) - graph = GraphFactory( - params=self._get_graph_params({'sort': 'barcode'}) - ) + graph = GraphFactory(params=self._get_graph_params({"sort": "barcode"})) qs = graph.build_queryset() - self.assertTrue(qs.first()['barcode'] < qs.last()['barcode']) + self.assertTrue(qs.first()["barcode"] < qs.last()["barcode"]) def test_key_sort_sorts_records_descending_when_minus_present(self): self.data_center_assets = DataCenterAssetFullFactory.create_batch(10) - graph = GraphFactory( - params=self._get_graph_params({'sort': '-barcode'}) - ) + graph = GraphFactory(params=self._get_graph_params({"sort": "-barcode"})) qs = graph.build_queryset() - self.assertTrue(qs.first()['barcode'] > qs.last()['barcode']) + self.assertTrue(qs.first()["barcode"] > qs.last()["barcode"]) class LabelGroupingTest(TestCase): - def _get_graph_params(self, update): data = { - 'filters': { - 'delivery_date__gte': '2016-01-01', - 'delivery_date__lt': '2017-01-01', + "filters": { + "delivery_date__gte": "2016-01-01", + "delivery_date__lt": "2017-01-01", }, - 'series': 'id', + "series": "id", } data.update(update) return data def test_label_works_when_no_grouping_in_label(self): self.a_2016 = DataCenterAssetFactory.create_batch( - 2, delivery_date='2015-01-01', + 2, + delivery_date="2015-01-01", ) expected = DataCenterAssetFactory.create_batch( - 1, delivery_date='2016-01-01', + 1, + delivery_date="2016-01-01", ) self.a_2015 = DataCenterAssetFactory.create_batch( - 3, delivery_date='2017-01-01', + 3, + delivery_date="2017-01-01", ) graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, - params=self._get_graph_params({ - 'labels': 'delivery_date', - }) + params=self._get_graph_params( + { + "labels": "delivery_date", + } + ), ) qs = graph.build_queryset() - self.assertEqual(qs.get()['series'], len(expected)) - self.assertIn('delivery_date', qs.get()) + self.assertEqual(qs.get()["series"], len(expected)) + self.assertIn("delivery_date", qs.get()) def test_label_works_when_year_grouping(self): self.a_2016 = DataCenterAssetFactory.create_batch( - 2, delivery_date='2015-01-01', + 2, + delivery_date="2015-01-01", ) expected = DataCenterAssetFactory.create_batch( - 1, delivery_date='2016-01-01', + 1, + delivery_date="2016-01-01", ) self.a_2015 = DataCenterAssetFactory.create_batch( - 3, delivery_date='2017-01-01', + 3, + delivery_date="2017-01-01", ) graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, - params=self._get_graph_params({ - 'labels': 'delivery_date|year', - }) + params=self._get_graph_params( + { + "labels": "delivery_date|year", + } + ), ) qs = graph.build_queryset() - self.assertEqual(qs.get()['series'], len(expected)) - self.assertIn('year', qs.get()) + self.assertEqual(qs.get()["series"], len(expected)) + self.assertIn("year", qs.get()) def _genenrate_dca_with_scan(self, count, date_str): gen = [] @@ -263,54 +254,52 @@ def _genenrate_dca_with_scan(self, count, date_str): return gen def test_label_works_when_year_grouping_on_foreign_key(self): - self._genenrate_dca_with_scan(2, '2015-01-01') - expected = self._genenrate_dca_with_scan(1, '2016-01-01') - self._genenrate_dca_with_scan(3, '2017-01-01') + self._genenrate_dca_with_scan(2, "2015-01-01") + expected = self._genenrate_dca_with_scan(1, "2016-01-01") + self._genenrate_dca_with_scan(3, "2017-01-01") graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, params={ - 'filters': { - 'securityscan__last_scan_date__gte': '2016-01-01', - 'securityscan__last_scan_date__lt': '2017-01-01', + "filters": { + "securityscan__last_scan_date__gte": "2016-01-01", + "securityscan__last_scan_date__lt": "2017-01-01", }, - 'series': 'id', - 'labels': 'securityscan__last_scan_date|year', - } + "series": "id", + "labels": "securityscan__last_scan_date|year", + }, ) qs = graph.build_queryset() - self.assertEqual(qs.get()['series'], len(expected)) - self.assertIn('year', qs.get()) + self.assertEqual(qs.get()["series"], len(expected)) + self.assertIn("year", qs.get()) def test_label_works_when_month_grouping_on_foreign_key(self): - self._genenrate_dca_with_scan(2, '2015-01-01') - expected = self._genenrate_dca_with_scan(1, '2016-01-01') - self._genenrate_dca_with_scan(3, '2017-01-01') + self._genenrate_dca_with_scan(2, "2015-01-01") + expected = self._genenrate_dca_with_scan(1, "2016-01-01") + self._genenrate_dca_with_scan(3, "2017-01-01") graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, params={ - 'filters': { - 'securityscan__last_scan_date__gte': '2016-01-01', - 'securityscan__last_scan_date__lt': '2017-01-01', + "filters": { + "securityscan__last_scan_date__gte": "2016-01-01", + "securityscan__last_scan_date__lt": "2017-01-01", }, - 'series': 'id', - 'labels': 'securityscan__last_scan_date|month', - } + "series": "id", + "labels": "securityscan__last_scan_date|month", + }, ) qs = graph.build_queryset() - self.assertEqual(qs.get()['series'], len(expected)) - self.assertIn('month', qs.get()) + self.assertEqual(qs.get()["series"], len(expected)) + self.assertIn("month", qs.get()) def test_ratio_aggregation(self): - service_env = ServiceEnvironmentFactory(service__name='sample-service') - vulnerability = VulnerabilityFactory( - patch_deadline=datetime.date(2015, 1, 1) - ) + service_env = ServiceEnvironmentFactory(service__name="sample-service") + vulnerability = VulnerabilityFactory(patch_deadline=datetime.date(2015, 1, 1)) for is_patched in [True, False]: for _ in range(3): dca = DataCenterAssetFactory(service_env=service_env) @@ -324,106 +313,97 @@ def test_ratio_aggregation(self): graph = GraphFactory( aggregate_type=AggregateType.aggregate_ratio.id, params={ - 'series': ['securityscan__is_patched', 'id'], - 'labels': 'service_env__service__name', - 'filters': { - 'series__gt': 0, - } - } + "series": ["securityscan__is_patched", "id"], + "labels": "service_env__service__name", + "filters": { + "series__gt": 0, + }, + }, ) qs = graph.build_queryset() - self.assertEqual(qs.get(), { - 'series': 50, - 'service_env__service__name': 'sample-service' - }) + self.assertEqual( + qs.get(), {"series": 50, "service_env__service__name": "sample-service"} + ) def test_duplicates_works_when_used_in_series_value(self): SecurityScanFactory( base_object=DataCenterAssetFactory().baseobject_ptr, vulnerabilities=[ VulnerabilityFactory( - patch_deadline=datetime.datetime.strptime( - '2015-01-01', '%Y-%m-%d' - ) + patch_deadline=datetime.datetime.strptime("2015-01-01", "%Y-%m-%d") ), - ] + ], ) SecurityScanFactory( base_object=DataCenterAssetFactory().baseobject_ptr, vulnerabilities=[ VulnerabilityFactory( - patch_deadline=datetime.datetime.strptime( - '2016-01-01', '%Y-%m-%d' - ) + patch_deadline=datetime.datetime.strptime("2016-01-01", "%Y-%m-%d") ), VulnerabilityFactory( - patch_deadline=datetime.datetime.strptime( - '2016-02-02', '%Y-%m-%d' - ) + patch_deadline=datetime.datetime.strptime("2016-02-02", "%Y-%m-%d") ), VulnerabilityFactory( - patch_deadline=datetime.datetime.strptime( - '2016-03-03', '%Y-%m-%d' - ) + patch_deadline=datetime.datetime.strptime("2016-03-03", "%Y-%m-%d") ), - ] + ], ) graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, params={ - 'filters': { - 'patch_deadline__gte': '2010-01-01', - 'securityscan__base_object__isnull': False, + "filters": { + "patch_deadline__gte": "2010-01-01", + "securityscan__base_object__isnull": False, }, - 'series': 'securityscan|distinct', - 'labels': 'patch_deadline|year', - } + "series": "securityscan|distinct", + "labels": "patch_deadline|year", + }, ) graph.model = ContentType.objects.get_for_model(Vulnerability) graph.save() qs = graph.build_queryset() - self.assertEqual(qs.all()[0]['series'], 1) - self.assertEqual(qs.all()[1]['series'], 1) + self.assertEqual(qs.all()[0]["series"], 1) + self.assertEqual(qs.all()[1]["series"], 1) def test_count_aggregate_with_zeros(self): assets_num = 2 DataCenterAssetFactory.create_batch(assets_num) graph = GraphFactory( aggregate_type=AggregateType.aggregate_count.id, - params=self._get_graph_params({ - 'aggregate_expression': 'scmstatuscheck', - 'filters': {}, - 'labels': 'id', - 'series': 'id', - }) + params=self._get_graph_params( + { + "aggregate_expression": "scmstatuscheck", + "filters": {}, + "labels": "id", + "series": "id", + } + ), ) qs = graph.build_queryset() self.assertEqual(qs.count(), assets_num) for item in qs.all(): - self.assertEqual(item['series'], 0) + self.assertEqual(item["series"], 0) def test_count_aggregate_sum_bool_values(self): assets_num = 2 a, b = DataCenterAssetFactory.create_batch(assets_num) - SCMStatusCheckFactory( - base_object=a, check_result=SCMCheckResult.scm_ok.id - ) - SCMStatusCheckFactory( - base_object=b, check_result=SCMCheckResult.scm_error.id - ) + SCMStatusCheckFactory(base_object=a, check_result=SCMCheckResult.scm_ok.id) + SCMStatusCheckFactory(base_object=b, check_result=SCMCheckResult.scm_error.id) graph = GraphFactory( aggregate_type=AggregateType.aggregate_sum_bool_values.id, - params=self._get_graph_params({ - 'filters': {}, - 'labels': 'id', - 'series': 'scmstatuscheck__ok', - }) + params=self._get_graph_params( + { + "filters": {}, + "labels": "id", + "series": "scmstatuscheck__ok", + } + ), ) qs = graph.build_queryset() - self.assertTrue(qs.get(id=a.id)['series'] == 1) - self.assertTrue(qs.get(id=b.id)['series'] == 0) + self.assertTrue(qs.get(id=a.id)["series"] == 1) + self.assertTrue(qs.get(id=b.id)["series"] == 0) diff --git a/src/ralph/dashboards/tests/test_renderer.py b/src/ralph/dashboards/tests/test_renderer.py index e8e4520020..83e77ff973 100644 --- a/src/ralph/dashboards/tests/test_renderer.py +++ b/src/ralph/dashboards/tests/test_renderer.py @@ -5,35 +5,31 @@ class BuildFilterTestCase(SimpleTestCase): def test_without_aggregation(self): - self.assertEqual( - build_filters(labels='id', value=10), - {'id': 10} - ) + self.assertEqual(build_filters(labels="id", value=10), {"id": 10}) def test_with_year_aggregation(self): self.assertEqual( - build_filters(labels='patchdeadline|year', value=2017), + build_filters(labels="patchdeadline|year", value=2017), { - 'patchdeadline__gte': '2017-01-01', - 'patchdeadline__lte': '2017-12-31', - } + "patchdeadline__gte": "2017-01-01", + "patchdeadline__lte": "2017-12-31", + }, ) def test_with_month_aggregation(self): self.assertEqual( - build_filters(labels='patchdeadline|month', value='2017-12'), + build_filters(labels="patchdeadline|month", value="2017-12"), { - 'patchdeadline__gte': '2017-12-01', - 'patchdeadline__lte': '2017-12-31', - } + "patchdeadline__gte": "2017-12-01", + "patchdeadline__lte": "2017-12-31", + }, ) def test_with_day_aggregation(self): self.assertEqual( - build_filters(labels='patchdeadline|day', value='2017-12-01'), + build_filters(labels="patchdeadline|day", value="2017-12-01"), { - 'patchdeadline__gte': '2017-12-01 00:00:00', - 'patchdeadline__lte': '2017-12-01 23:59:59', - } + "patchdeadline__gte": "2017-12-01 00:00:00", + "patchdeadline__lte": "2017-12-01 23:59:59", + }, ) - diff --git a/src/ralph/dashboards/urls.py b/src/ralph/dashboards/urls.py index 13bc2d37ab..aeee4d025d 100644 --- a/src/ralph/dashboards/urls.py +++ b/src/ralph/dashboards/urls.py @@ -4,8 +4,8 @@ urlpatterns = [ url( - r'^dashboard_view/(?P\d+)/$', + r"^dashboard_view/(?P\d+)/$", DashboardView.as_view(), - name='dashboard_view' + name="dashboard_view", ), ] diff --git a/src/ralph/dashboards/views.py b/src/ralph/dashboards/views.py index 126541da5c..86bc9c9958 100644 --- a/src/ralph/dashboards/views.py +++ b/src/ralph/dashboards/views.py @@ -4,23 +4,21 @@ class DashboardView(TemplateView): - template_name = 'dashboard/dashboard.html' + template_name = "dashboard/dashboard.html" def dispatch(self, request, dashboard_id, *args, **kwargs): self.dashboard = Dashboard.objects.get(id=dashboard_id, active=True) return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): - kwargs['graphs'] = [] - rendered_graphs = '' - for graph in self.dashboard.graphs.filter(active=True).order_by('pk'): + kwargs["graphs"] = [] + rendered_graphs = "" + for graph in self.dashboard.graphs.filter(active=True).order_by("pk"): rendered_graphs += graph.render( - name='dashboard_{}_graph_{}'.format( - self.dashboard.id, graph.id - ) + name="dashboard_{}_graph_{}".format(self.dashboard.id, graph.id) ) - kwargs['name'] = self.dashboard.name - kwargs['interval'] = self.dashboard.interval - kwargs['description'] = self.dashboard.description - kwargs['rendered_graphs'] = rendered_graphs + kwargs["name"] = self.dashboard.name + kwargs["interval"] = self.dashboard.interval + kwargs["description"] = self.dashboard.description + kwargs["rendered_graphs"] = rendered_graphs return super().get(request, *args, **kwargs) diff --git a/src/ralph/data_center/__init__.py b/src/ralph/data_center/__init__.py index 8c65acb16f..e3f312fbc3 100644 --- a/src/ralph/data_center/__init__.py +++ b/src/ralph/data_center/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.data_center.apps.DataCenterConfig' +default_app_config = "ralph.data_center.apps.DataCenterConfig" diff --git a/src/ralph/data_center/admin.py b/src/ralph/data_center/admin.py index 24af936b21..925e477cbf 100644 --- a/src/ralph/data_center/admin.py +++ b/src/ralph/data_center/admin.py @@ -22,14 +22,14 @@ RelatedAutocompleteFieldListFilter, TagsListFilter, TreeRelatedAutocompleteFilterWithDescendants, - VulnerabilitesByPatchDeadline + VulnerabilitesByPatchDeadline, ) from ralph.admin.helpers import generate_html_link from ralph.admin.mixins import ( BulkEditChangeListMixin, RalphAdmin, RalphAdminImportExportMixin, - RalphTabularInline + RalphTabularInline, ) from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.admin.views.main import RalphChangeList @@ -41,7 +41,7 @@ from ralph.attachments.admin import AttachmentsMixin from ralph.configuration_management.views import ( SCMCheckInfo, - SCMStatusCheckInChangeListMixin + SCMStatusCheckInChangeListMixin, ) from ralph.data_center.forms import DataCenterAssetForm from ralph.data_center.models.components import DiskShare, DiskShareMount @@ -53,14 +53,14 @@ DataCenterAsset, Rack, RackAccessory, - ServerRoom + ServerRoom, ) from ralph.data_center.models.virtual import ( BaseObjectCluster, Cluster, ClusterType, Database, - VIP + VIP, ) from ralph.data_center.views import RelationsView from ralph.data_importer import resources @@ -76,31 +76,29 @@ from ralph.supports.models import BaseObjectsSupport -def generate_list_filter_with_common_fields( - prefix=None, postfix=None -): +def generate_list_filter_with_common_fields(prefix=None, postfix=None): result = [] if type(prefix) == list: result.extend(prefix) result.extend( [ - 'service_env', - 'configuration_path__path', + "service_env", + "configuration_path__path", ( - 'configuration_path__module', - TreeRelatedAutocompleteFilterWithDescendants + "configuration_path__module", + TreeRelatedAutocompleteFilterWithDescendants, ), MacAddressFilter, IPFilter, ( - 'securityscan__vulnerabilities__patch_deadline', - VulnerabilitesByPatchDeadline + "securityscan__vulnerabilities__patch_deadline", + VulnerabilitesByPatchDeadline, ), ( - 'securityscan__vulnerabilities', - filters.RelatedAutocompleteFieldListFilter + "securityscan__vulnerabilities", + filters.RelatedAutocompleteFieldListFilter, ), - 'securityscan__is_patched', + "securityscan__is_patched", ] ) if type(postfix) == list: @@ -112,48 +110,44 @@ class DCHostTypeListFilter(ChoicesListFilter): def __init__(self, *args, **kwargs): from ralph.data_center.models import Cluster, DataCenterAsset from ralph.virtual.models import CloudHost, VirtualServer + models = [Cluster, DataCenterAsset, CloudHost, VirtualServer] self.choices_list = [ - ( - ContentType.objects.get_for_model(model).pk, - model._meta.verbose_name - ) + (ContentType.objects.get_for_model(model).pk, model._meta.verbose_name) for model in models ] super().__init__(*args, **kwargs) class DCHostHostnameFilter(SimpleListFilter): - title = _('Hostname') - parameter_name = 'hostname' - template = 'admin/filters/text_filter.html' + title = _("Hostname") + parameter_name = "hostname" + template = "admin/filters/text_filter.html" def queryset(self, request, queryset): if not self.value(): return queryset fields = [ - 'asset__hostname', - 'cloudhost__hostname', - 'cluster__hostname', - 'virtualserver__hostname', - 'ethernet_set__ipaddress__hostname' + "asset__hostname", + "cloudhost__hostname", + "cluster__hostname", + "virtualserver__hostname", + "ethernet_set__ipaddress__hostname", ] # TODO: simple if hostname would be in one model queries = [ - Q(**{'{}__icontains'.format(field): self.value().strip()}) + Q(**{"{}__icontains".format(field): self.value().strip()}) for field in fields ] return queryset.filter(reduce(operator.or_, queries)).distinct() def lookups(self, request, model_admin): - return ( - (1, _('Hostname')), - ) + return ((1, _("Hostname")),) def choices(self, cl): yield { - 'selected': self.value(), - 'parameter_name': self.parameter_name, + "selected": self.value(), + "parameter_name": self.parameter_name, } @@ -166,25 +160,24 @@ class ClusterDNSView(DNSView): @register(Accessory) class AccessoryAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] class ClusterNetworkInline(RalphTabularInline): form = SimpleNetworkWithManagementIPForm model = Ethernet - exclude = ['model'] + exclude = ["model"] class ClusterLicencesView(RalphDetailViewAdmin): - icon = 'key' - name = 'cluster_licences' - label = _('Licences') - url_name = 'licences' + icon = "key" + name = "cluster_licences" + label = _("Licences") + url_name = "licences" class ClusterLicenceInline(RalphTabularInline): model = BaseObjectLicence - raw_id_fields = ('licence',) + raw_id_fields = ("licence",) extra = 1 inlines = [ClusterLicenceInline] @@ -192,30 +185,40 @@ class ClusterLicenceInline(RalphTabularInline): @register(ClusterType) class ClusterTypeAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(Cluster) class ClusterAdmin(CustomFieldValueAdminMixin, RalphAdmin): - - search_fields = ['name', 'hostname', 'ethernet_set__ipaddress__hostname'] + search_fields = ["name", "hostname", "ethernet_set__ipaddress__hostname"] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', 'hostname', 'type', 'status', 'remarks', 'service_env', - 'configuration_path', - 'tags' - ) - }), + ( + _("Basic info"), + { + "fields": ( + "name", + "hostname", + "type", + "status", + "remarks", + "service_env", + "configuration_path", + "tags", + ) + }, + ), ) - raw_id_fields = ['service_env', 'configuration_path'] - readonly_fields = ['get_masters_summary'] - list_display = ['id', 'name', 'hostname', 'type'] - list_select_related = ['type'] + raw_id_fields = ["service_env", "configuration_path"] + readonly_fields = ["get_masters_summary"] + list_display = ["id", "name", "hostname", "type"] + list_select_related = ["type"] list_filter = [ - 'name', BaseObjectHostnameFilter, 'type', 'service_env', - 'configuration_path', 'status' + "name", + BaseObjectHostnameFilter, + "type", + "service_env", + "configuration_path", + "status", ] change_views = [ClusterLicencesView] if settings.ENABLE_DNSAAS_INTEGRATION: @@ -223,10 +226,10 @@ class ClusterAdmin(CustomFieldValueAdminMixin, RalphAdmin): class ClusterBaseObjectInline(RalphTabularInline): model = BaseObjectCluster - fk_name = 'cluster' - raw_id_fields = ('base_object',) + fk_name = "cluster" + raw_id_fields = ("base_object",) extra = 1 - verbose_name = _('Base Object') + verbose_name = _("Base Object") inlines = [ClusterBaseObjectInline, ClusterNetworkInline] @@ -237,35 +240,38 @@ def get_fieldsets(self, request, obj=None): """ fieldsets = super().get_fieldsets(request, obj) if obj and obj.pk and obj.type.show_master_summary: - fieldsets += (( - _('Master Info'), { - 'fields': ( - 'get_masters_summary', - ) - } - ),) + fieldsets += ((_("Master Info"), {"fields": ("get_masters_summary",)}),) return fieldsets @mark_safe def get_masters_summary(self, obj): masters = obj.masters if not masters: - return '-' + return "-" return Table( masters, - getattr(masters[0], '_summary_fields', []), + getattr(masters[0], "_summary_fields", []), transpose=True, ).render() - get_masters_summary.short_description = _('Master info') + + get_masters_summary.short_description = _("Master info") @register(DataCenter) class DataCenterAdmin(RalphAdmin): - list_display = ['name', 'company', 'country', 'city', 'address', - 'latitude', 'longitude', 'type', 'shortcut'] - search_fields = ['name', 'shortcut'] - list_filter = ['name', 'company', 'country', 'city', 'address', 'type', - 'shortcut'] + list_display = [ + "name", + "company", + "country", + "city", + "address", + "latitude", + "longitude", + "type", + "shortcut", + ] + search_fields = ["name", "shortcut"] + list_filter = ["name", "company", "country", "city", "address", "type", "shortcut"] class DataCenterAssetNetworkView(NetworkWithTerminatorsView): @@ -273,30 +279,30 @@ class DataCenterAssetNetworkView(NetworkWithTerminatorsView): class DataCenterAssetSupport(RalphDetailViewAdmin): - icon = 'bookmark' - name = 'dc_asset_support' - label = _('Supports') - url_name = 'data_center_asset_support' + icon = "bookmark" + name = "dc_asset_support" + label = _("Supports") + url_name = "data_center_asset_support" class DataCenterAssetSupportInline(RalphTabularInline): model = BaseObjectsSupport - raw_id_fields = ('support',) + raw_id_fields = ("support",) extra = 1 - verbose_name = _('Support') - ordering = ['-support__date_to'] + verbose_name = _("Support") + ordering = ["-support__date_to"] inlines = [DataCenterAssetSupportInline] class DataCenterAssetLicence(RalphDetailViewAdmin): - icon = 'key' - name = 'dc_asset_licences' - label = _('Licences') - url_name = 'data_center_asset_licences' + icon = "key" + name = "dc_asset_licences" + label = _("Licences") + url_name = "data_center_asset_licences" class DataCenterAssetLicenceInline(RalphTabularInline): model = BaseObjectLicence - raw_id_fields = ('licence',) + raw_id_fields = ("licence",) extra = 1 inlines = [DataCenterAssetLicenceInline] @@ -307,13 +313,13 @@ class DataCenterAssetComponents(ComponentsAdminView): class DataCenterAssetOperation(OperationViewReadOnlyForExisiting): - name = 'dc_asset_operations' - url_name = 'data_center_asset_operations' + name = "dc_asset_operations" + url_name = "data_center_asset_operations" inlines = OperationViewReadOnlyForExisiting.admin_class.inlines class DataCenterAssetSecurityInfo(SecurityInfo): - url_name = 'datacenter_asset_security_info' + url_name = "datacenter_asset_security_info" class DataCenterAssetChangeList(RalphChangeList): @@ -322,10 +328,10 @@ def get_ordering(self, request, queryset): # NOTE(romcheg): slot_no is added by Django Admin automatically. location_fields = [ - 'rack__server_room__data_center__name', - 'rack__server_room__name', - 'rack__name', - 'position', + "rack__server_room__data_center__name", + "rack__server_room__name", + "rack__name", + "position", ] ordering = super(DataCenterAssetChangeList, self).get_ordering( @@ -334,16 +340,13 @@ def get_ordering(self, request, queryset): params = self.params if ORDER_VAR in params: - - order_params = params[ORDER_VAR].split('.') + order_params = params[ORDER_VAR].split(".") for insert_index, p in enumerate(order_params): try: - none, pfx, idx = p.rpartition('-') - if self.list_display[int(idx)] == 'show_location': - + none, pfx, idx = p.rpartition("-") + if self.list_display[int(idx)] == "show_location": ordering[insert_index:insert_index] = [ - '{}{}'.format(pfx, field) - for field in location_fields + "{}{}".format(pfx, field) for field in location_fields ] except (IndexError, ValueError): continue # Invalid ordering specified, skip it. @@ -352,11 +355,11 @@ def get_ordering(self, request, queryset): class DataCenterAssetSCMInfo(SCMCheckInfo): - url_name = 'datacenterasset_scm_info' + url_name = "datacenterasset_scm_info" class DataCenterAssetRelationsView(RelationsView): - url = 'datacenterasset_relations' + url = "datacenterasset_relations" @register(DataCenterAsset) @@ -374,8 +377,8 @@ class DataCenterAssetAdmin( ): """Data Center Asset admin class.""" - add_form_template = 'data_center/datacenterasset/add_form.html' - actions = ['bulk_edit_action'] + add_form_template = "data_center/datacenterasset/add_form.html" + actions = ["bulk_edit_action"] change_views = [ DataCenterAssetComponents, DataCenterAssetNetworkView, @@ -392,157 +395,235 @@ class DataCenterAssetAdmin( show_transition_history = True resource_class = resources.DataCenterAssetResource list_display = [ - 'hostname', - 'status', - 'barcode', - 'model', - 'sn', - 'invoice_date', - 'invoice_no', - 'show_location', - 'service_env', - 'configuration_path', - 'scan_status', - 'scm_status_check', - 'property_of', - 'order_no' + "hostname", + "status", + "barcode", + "model", + "sn", + "invoice_date", + "invoice_no", + "show_location", + "service_env", + "configuration_path", + "scan_status", + "scm_status_check", + "property_of", + "order_no", ] - multiadd_summary_fields = list_display + ['rack'] - one_of_mulitvalue_required = ['sn', 'barcode'] + multiadd_summary_fields = list_display + ["rack"] + one_of_mulitvalue_required = ["sn", "barcode"] bulk_edit_list = [ - 'hostname', 'status', 'barcode', 'model', 'sn', 'invoice_date', - 'invoice_no', 'rack', 'orientation', 'position', 'slot_no', 'price', - 'provider', 'service_env', 'configuration_path', 'tags', 'start_usage', - 'depreciation_end_date', 'depreciation_rate', 'order_no', 'remarks', - 'property_of' + "hostname", + "status", + "barcode", + "model", + "sn", + "invoice_date", + "invoice_no", + "rack", + "orientation", + "position", + "slot_no", + "price", + "provider", + "service_env", + "configuration_path", + "tags", + "start_usage", + "depreciation_end_date", + "depreciation_rate", + "order_no", + "remarks", + "property_of", ] - bulk_edit_no_fillable = ['barcode', 'sn'] + bulk_edit_no_fillable = ["barcode", "sn"] search_fields = [ - 'barcode', 'sn', 'hostname', 'invoice_no', 'order_no', - 'ethernet_set__ipaddress__address', 'ethernet_set__ipaddress__hostname' + "barcode", + "sn", + "hostname", + "invoice_no", + "order_no", + "ethernet_set__ipaddress__address", + "ethernet_set__ipaddress__hostname", ] - list_filter_prefix = ['hostname'] + list_filter_prefix = ["hostname"] list_filter_postfix = [ - 'invoice_no', 'invoice_date', 'status', 'barcode', 'sn', - 'order_no', 'model__name', - ('model__category', RelatedAutocompleteFieldListFilter), - 'depreciation_end_date', 'force_depreciation', 'remarks', - 'budget_info', 'rack', 'rack__server_room', - 'rack__server_room__data_center', 'position', 'property_of', - LiquidatedStatusFilter, TagsListFilter, - 'fibrechannelcard_set__wwn' + "invoice_no", + "invoice_date", + "status", + "barcode", + "sn", + "order_no", + "model__name", + ("model__category", RelatedAutocompleteFieldListFilter), + "depreciation_end_date", + "force_depreciation", + "remarks", + "budget_info", + "rack", + "rack__server_room", + "rack__server_room__data_center", + "position", + "property_of", + LiquidatedStatusFilter, + TagsListFilter, + "fibrechannelcard_set__wwn", ] list_filter = generate_list_filter_with_common_fields( - list_filter_prefix, - list_filter_postfix + list_filter_prefix, list_filter_postfix ) - date_hierarchy = 'created' + date_hierarchy = "created" list_select_related = [ - 'model', - 'model__manufacturer', - 'model__category', - 'rack', - 'rack__server_room', - 'rack__server_room__data_center', - 'service_env', - 'service_env__service', - 'service_env__environment', - 'configuration_path', - 'property_of', - 'parent', - 'budget_info', + "model", + "model__manufacturer", + "model__category", + "rack", + "rack__server_room", + "rack__server_room__data_center", + "service_env", + "service_env__service", + "service_env__environment", + "configuration_path", + "property_of", + "parent", + "budget_info", ] raw_id_fields = [ - 'model', 'rack', 'service_env', 'parent', 'budget_info', - 'configuration_path', + "model", + "rack", + "service_env", + "parent", + "budget_info", + "configuration_path", ] - raw_id_override_parent = {'parent': DataCenterAsset} - _invoice_report_name = 'invoice-data-center-asset' - readonly_fields = ['get_created_date', 'go_to_visualization'] + raw_id_override_parent = {"parent": DataCenterAsset} + _invoice_report_name = "invoice-data-center-asset" + readonly_fields = ["get_created_date", "go_to_visualization"] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'hostname', 'model', 'status', 'barcode', 'sn', 'niw', - 'required_support', 'remarks', 'tags', 'property_of', - 'firmware_version', 'bios_version', - ) - }), - (_('Location Info'), { - 'fields': ( - 'rack', 'position', 'orientation', 'slot_no', 'parent', - 'management_ip', 'management_hostname', 'go_to_visualization' - ) - }), - (_('Usage info'), { - 'fields': ( - 'service_env', 'configuration_path', 'production_year', - 'production_use_date', - ) - }), - (_('Financial & Order Info'), { - 'fields': ( - 'order_no', 'invoice_date', 'invoice_no', 'task_url', 'price', - 'vendor_contract_number', 'leasing_rate', - 'depreciation_rate', 'depreciation_end_date', - 'force_depreciation', 'source', 'provider', 'delivery_date', - 'budget_info', 'start_usage', 'get_created_date', - ) - }), + ( + _("Basic info"), + { + "fields": ( + "hostname", + "model", + "status", + "barcode", + "sn", + "niw", + "required_support", + "remarks", + "tags", + "property_of", + "firmware_version", + "bios_version", + ) + }, + ), + ( + _("Location Info"), + { + "fields": ( + "rack", + "position", + "orientation", + "slot_no", + "parent", + "management_ip", + "management_hostname", + "go_to_visualization", + ) + }, + ), + ( + _("Usage info"), + { + "fields": ( + "service_env", + "configuration_path", + "production_year", + "production_use_date", + ) + }, + ), + ( + _("Financial & Order Info"), + { + "fields": ( + "order_no", + "invoice_date", + "invoice_no", + "task_url", + "price", + "vendor_contract_number", + "leasing_rate", + "depreciation_rate", + "depreciation_end_date", + "force_depreciation", + "source", + "provider", + "delivery_date", + "budget_info", + "start_usage", + "get_created_date", + ) + }, + ), ) def get_export_queryset(self, request): qs = ( super(RalphAdminImportExportMixin, self) .get_export_queryset(request) - .select_related( - *self.list_select_related - ) + .select_related(*self.list_select_related) ) if isinstance(qs, BaseObjectPolymorphicQuerySet): return qs.polymorphic_prefetch_related( DataCenterAsset=[ - 'tags', - 'ethernet_set__ipaddress', - 'parent__ethernet_set__ipaddress' + "tags", + "ethernet_set__ipaddress", + "parent__ethernet_set__ipaddress", ] ) else: return qs.prefetch_related( - 'tags', 'ethernet_set__ipaddress', 'parent__ethernet_set__ipaddress' + "tags", "ethernet_set__ipaddress", "parent__ethernet_set__ipaddress" ) def get_multiadd_fields(self, obj=None): multiadd_fields = [ - {'field': 'sn', 'allow_duplicates': False}, - {'field': 'barcode', 'allow_duplicates': False}, + {"field": "sn", "allow_duplicates": False}, + {"field": "barcode", "allow_duplicates": False}, ] - return getattr( - settings, 'MULTIADD_DATA_CENTER_ASSET_FIELDS', None - ) or multiadd_fields + return ( + getattr(settings, "MULTIADD_DATA_CENTER_ASSET_FIELDS", None) + or multiadd_fields + ) @mark_safe def go_to_visualization(self, obj): if not obj.rack: - return '—' - url = '{}#/sr/{}/rack/{}'.format( - reverse('dc_view'), + return "—" + url = "{}#/sr/{}/rack/{}".format( + reverse("dc_view"), obj.rack.server_room_id, obj.rack.id, ) - label = ' / '.join(obj.get_location()) + label = " / ".join(obj.get_location()) return generate_html_link(url, label=label, params={}) - go_to_visualization.short_description = _('Visualization') + + go_to_visualization.short_description = _("Visualization") @mark_safe def show_location(self, obj): return obj.location - show_location.short_description = _('Location') + + show_location.short_description = _("Location") # NOTE(romcheg): Django Admin can only order custom fields by one field. # The rest of the ordering is configured in # DataCenterAssetChangeList.get_ordering() - show_location.admin_order_field = 'slot_no' + show_location.admin_order_field = "slot_no" def get_created_date(self, obj): """ @@ -550,8 +631,9 @@ def get_created_date(self, obj): permissions, it cannot be displayed directly, because only superuser will see it) """ - return obj.created or '-' - get_created_date.short_description = _('Created at') + return obj.created or "-" + + get_created_date.short_description = _("Created at") def get_changelist(self, request, **kwargs): return DataCenterAssetChangeList @@ -559,11 +641,10 @@ def get_changelist(self, request, **kwargs): @register(ServerRoom) class ServerRoomAdmin(RalphAdmin): - - list_select_related = ['data_center'] - search_fields = ['name', 'data_center__name'] + list_select_related = ["data_center"] + search_fields = ["name", "data_center__name"] resource_class = resources.ServerRoomResource - list_display = ['name', 'data_center'] + list_display = ["name", "data_center"] class RackAccessoryInline(RalphTabularInline): @@ -572,34 +653,35 @@ class RackAccessoryInline(RalphTabularInline): @register(Rack) class RackAdmin(RalphAdmin): - - exclude = ['accessories'] + exclude = ["accessories"] list_display = [ - 'name', - 'server_room_name', - 'data_center_name', - 'reverse_ordering', + "name", + "server_room_name", + "data_center_name", + "reverse_ordering", ] - list_filter = ['server_room__data_center'] # TODO use fk field in filter - list_select_related = ['server_room', 'server_room__data_center'] - search_fields = ['name'] + list_filter = ["server_room__data_center"] # TODO use fk field in filter + list_select_related = ["server_room", "server_room__data_center"] + search_fields = ["name"] inlines = [RackAccessoryInline] resource_class = resources.RackResource def server_room_name(self, obj): - return obj.server_room.name if obj.server_room else '' - server_room_name.short_description = _('Server room') - server_room_name.admin_order_field = 'server_room__name' + return obj.server_room.name if obj.server_room else "" + + server_room_name.short_description = _("Server room") + server_room_name.admin_order_field = "server_room__name" def data_center_name(self, obj): - return obj.server_room.data_center.name if obj.server_room else '' - data_center_name.short_description = _('Data Center') - data_center_name.admin_order_field = 'server_room__data_center__name' + return obj.server_room.data_center.name if obj.server_room else "" + + data_center_name.short_description = _("Data Center") + data_center_name.admin_order_field = "server_room__data_center__name" def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "server_room": kwargs["queryset"] = ServerRoom.objects.select_related( - 'data_center', + "data_center", ) return super(RackAdmin, self).formfield_for_foreignkey( db_field, request, **kwargs @@ -608,11 +690,10 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs): @register(RackAccessory) class RackAccessoryAdmin(RalphAdmin): - - list_select_related = ['rack', 'accessory'] - search_fields = ['accessory__name', 'rack__name'] - raw_id_fields = ['rack'] - list_display = ['__str__', 'position'] + list_select_related = ["rack", "accessory"] + search_fields = ["accessory__name", "rack__name"] + raw_id_fields = ["rack"] + list_display = ["__str__", "position"] resource_class = resources.RackAccessoryResource @@ -623,23 +704,26 @@ class DatabaseAdmin(RalphAdmin): @register(VIP) class VIPAdmin(RalphAdmin): - search_fields = ['name', 'ip__address'] - list_display = ['name', 'ip', 'port', 'protocol', 'service_env'] - list_filter = ['ip', 'port', 'protocol', 'service_env', 'parent'] - list_select_related = [ - 'ip', 'service_env__service', 'service_env__environment' - ] - raw_id_fields = ['ip', 'service_env', 'parent', 'configuration_path'] - raw_id_override_parent = {'parent': Cluster} + search_fields = ["name", "ip__address"] + list_display = ["name", "ip", "port", "protocol", "service_env"] + list_filter = ["ip", "port", "protocol", "service_env", "parent"] + list_select_related = ["ip", "service_env__service", "service_env__environment"] + raw_id_fields = ["ip", "service_env", "parent", "configuration_path"] + raw_id_override_parent = {"parent": Cluster} fields = ( - 'name', 'ip', 'port', 'protocol', 'service_env', 'parent', 'remarks', - 'tags' + "name", + "ip", + "port", + "protocol", + "service_env", + "parent", + "remarks", + "tags", ) @register(Connection) class ConnectionAdmin(RalphAdmin): - resource_class = resources.ConnectionResource @@ -659,50 +743,52 @@ def url_for_result(self, result): class DCHostSCMInfo(SCMCheckInfo): - url_name = 'dchost_scm_info' + url_name = "dchost_scm_info" @register(DCHost) class DCHostAdmin( - SCMStatusCheckInChangeListMixin, - ScanStatusInChangeListMixin, - RalphAdmin + SCMStatusCheckInChangeListMixin, ScanStatusInChangeListMixin, RalphAdmin ): - change_list_template = 'admin/data_center/dchost/change_list.html' + change_list_template = "admin/data_center/dchost/change_list.html" search_fields = [ - 'remarks', - 'asset__hostname', - 'cloudhost__hostname', - 'cluster__hostname', - 'virtualserver__hostname', - 'ethernet_set__ipaddress__address', - 'ethernet_set__ipaddress__hostname' + "remarks", + "asset__hostname", + "cloudhost__hostname", + "cluster__hostname", + "virtualserver__hostname", + "ethernet_set__ipaddress__address", + "ethernet_set__ipaddress__hostname", ] list_display = [ - 'get_hostname', - 'content_type', - 'service_env', - 'configuration_path', - 'show_location', - 'remarks', - 'scan_status', - 'scm_status_check' + "get_hostname", + "content_type", + "service_env", + "configuration_path", + "show_location", + "remarks", + "scan_status", + "scm_status_check", ] # TODO: sn # TODO: hostname, DC list_filter_prefix = [DCHostHostnameFilter] - list_filter_postfix = [('content_type', DCHostTypeListFilter,)] + list_filter_postfix = [ + ( + "content_type", + DCHostTypeListFilter, + ) + ] list_filter = generate_list_filter_with_common_fields( - list_filter_prefix, - list_filter_postfix + list_filter_prefix, list_filter_postfix ) list_select_related = [ - 'content_type', - 'configuration_path', - 'service_env', - 'service_env__environment', - 'service_env__service', + "content_type", + "configuration_path", + "service_env", + "service_env__environment", + "service_env__service", ] resource_class = resources.DCHostResource @@ -719,7 +805,7 @@ def get_actions(self, request): def get_hostname(self, obj): return obj.hostname - get_hostname.short_description = _('Hostname') + get_hostname.short_description = _("Hostname") # TODO: simple if hostname would be in one model # get_hostname.admin_order_field = 'asset__hostname' @@ -733,32 +819,31 @@ def _initialize_search_form(self, extra_context, fields_from_model=True): @mark_safe def show_location(self, obj): - if hasattr(obj, 'get_location'): - return ' / '.join(obj.get_location()) - return '' - show_location.short_description = _('Location') + if hasattr(obj, "get_location"): + return " / ".join(obj.get_location()) + return "" + + show_location.short_description = _("Location") def get_queryset(self, request): qs = super().get_queryset(request) # location polymorphic_select_related = dict( - DataCenterAsset=[ - 'rack__server_room__data_center', 'model' - ], + DataCenterAsset=["rack__server_room__data_center", "model"], VirtualServer=[ - 'parent__asset__datacenterasset__rack__server_room__data_center', # noqa + "parent__asset__datacenterasset__rack__server_room__data_center", # noqa ], - CloudHost=[ - 'hypervisor__rack__server_room__data_center' - ] + CloudHost=["hypervisor__rack__server_room__data_center"], ) qs = qs.polymorphic_select_related(**polymorphic_select_related) - qs = qs.polymorphic_prefetch_related(Cluster=[ - Prefetch( - 'baseobjectcluster_set__base_object', - queryset=BaseObject.polymorphic_objects.polymorphic_select_related( # noqa - **polymorphic_select_related + qs = qs.polymorphic_prefetch_related( + Cluster=[ + Prefetch( + "baseobjectcluster_set__base_object", + queryset=BaseObject.polymorphic_objects.polymorphic_select_related( # noqa + **polymorphic_select_related + ), ) - ) - ]) + ] + ) return qs diff --git a/src/ralph/data_center/api/routers.py b/src/ralph/data_center/api/routers.py index fdb57edab0..5abfe8a330 100644 --- a/src/ralph/data_center/api/routers.py +++ b/src/ralph/data_center/api/routers.py @@ -11,18 +11,18 @@ RackAccessoryViewSet, RackViewSet, ServerRoomViewSet, - VIPViewSet + VIPViewSet, ) -router.register(r'accessories', AccessoryViewSet) -router.register(r'databases', DatabaseViewSet) -router.register(r'data-centers', DataCenterViewSet) -router.register(r'data-center-assets', DataCenterAssetViewSet) -router.register(r'racks', RackViewSet) -router.register(r'rack-accessories', RackAccessoryViewSet) -router.register(r'server-rooms', ServerRoomViewSet) -router.register(r'vips', VIPViewSet) -router.register(r'clusters', ClusterViewSet) -router.register(r'cluster-types', ClusterTypeViewSet) -router.register(r'base-object-clusters', BaseObjectClusterViewSet) +router.register(r"accessories", AccessoryViewSet) +router.register(r"databases", DatabaseViewSet) +router.register(r"data-centers", DataCenterViewSet) +router.register(r"data-center-assets", DataCenterAssetViewSet) +router.register(r"racks", RackViewSet) +router.register(r"rack-accessories", RackAccessoryViewSet) +router.register(r"server-rooms", ServerRoomViewSet) +router.register(r"vips", VIPViewSet) +router.register(r"clusters", ClusterViewSet) +router.register(r"cluster-types", ClusterTypeViewSet) +router.register(r"base-object-clusters", BaseObjectClusterViewSet) urlpatterns = [] diff --git a/src/ralph/data_center/api/serializers.py b/src/ralph/data_center/api/serializers.py index c1da67464f..efcf2fdd5a 100644 --- a/src/ralph/data_center/api/serializers.py +++ b/src/ralph/data_center/api/serializers.py @@ -9,7 +9,7 @@ BaseObjectSerializer, ComponentSerializerMixin, NetworkComponentSerializerMixin, - OwnersFromServiceEnvSerializerMixin + OwnersFromServiceEnvSerializerMixin, ) from ralph.configuration_management.api import SCMInfoSerializer from ralph.data_center.models import ( @@ -23,7 +23,7 @@ Rack, RackAccessory, ServerRoom, - VIP + VIP, ) from ralph.security.api import SecurityScanSerializer @@ -38,37 +38,39 @@ class Meta: class ClusterSimpleSerializer(BaseObjectSerializer): class Meta(BaseObjectSerializer.Meta): model = Cluster - exclude = ('content_type',) + exclude = ("content_type",) depth = 1 class BaseObjectClusterSimpleSerializer(RalphAPISerializer): class Meta: model = BaseObjectCluster - fields = ('id', 'url', 'base_object', 'is_master') + fields = ("id", "url", "base_object", "is_master") class BaseObjectClusterSerializer(RalphAPISerializer): class Meta: model = BaseObjectCluster - fields = ('id', 'url', 'base_object', 'is_master', 'cluster') + fields = ("id", "url", "base_object", "is_master", "cluster") class ClusterSerializer( NetworkComponentSerializerMixin, OwnersFromServiceEnvSerializerMixin, - ClusterSimpleSerializer + ClusterSimpleSerializer, ): base_objects = BaseObjectClusterSimpleSerializer( - many=True, read_only=True, source='baseobjectcluster_set' + many=True, read_only=True, source="baseobjectcluster_set" ) masters = serializers.HyperlinkedRelatedField( - many=True, view_name='baseobject-detail', read_only=True, - source='get_masters' + many=True, view_name="baseobject-detail", read_only=True, source="get_masters" ) class Meta(ClusterSimpleSerializer.Meta): - exclude = ('parent', 'content_type',) + exclude = ( + "parent", + "content_type", + ) class DataCenterSerializer(RalphAPISerializer): @@ -92,7 +94,7 @@ class Meta: class RackAccessorySerializer(RalphAPISerializer): - name = serializers.ReadOnlyField(source='accessory.name') + name = serializers.ReadOnlyField(source="accessory.name") class Meta: model = RackAccessory @@ -103,12 +105,12 @@ class SimpleRackSerializer(RalphAPISerializer): class Meta: model = Rack depth = 2 - exclude = ('accessories',) + exclude = ("accessories",) class RackSerializer(RalphAPISerializer): accessories = RackAccessorySerializer( - read_only=True, many=True, source='rackaccessory_set' + read_only=True, many=True, source="rackaccessory_set" ) class Meta(SimpleRackSerializer.Meta): @@ -120,7 +122,7 @@ class Meta(SimpleRackSerializer.Meta): class DataCenterAssetSimpleSerializer(RalphAPISerializer): class Meta: model = DataCenterAsset - fields = ['id', 'hostname', 'url'] + fields = ["id", "hostname", "url"] _skip_tags_field = True @@ -133,6 +135,7 @@ class DataCenterAssetSerializer(ComponentSerializerMixin, AssetSerializer): def get_related_hosts(self, obj): from ralph.virtual.api import CloudHostSimpleSerializer from ralph.virtual.api import VirtualServerSimpleSerializer + # attributes "virtual_servers", "physical_servers" and "cloud_hosts" # are custom prefetches, see DataCenterAssetViewSet return { @@ -154,9 +157,7 @@ class Meta(AssetSerializer.Meta): class DataCenterAssetSaveSerializer(RalphAPISaveSerializer): rack = serializers.PrimaryKeyRelatedField( - allow_null=False, - required=True, - queryset=Rack.objects.all() + allow_null=False, required=True, queryset=Rack.objects.all() ) class Meta: diff --git a/src/ralph/data_center/api/views.py b/src/ralph/data_center/api/views.py index 2fb04708d0..d0c9e276f5 100644 --- a/src/ralph/data_center/api/views.py +++ b/src/ralph/data_center/api/views.py @@ -6,13 +6,13 @@ from ralph.assets.api.filters import NetworkableObjectFilters from ralph.assets.api.views import ( base_object_descendant_prefetch_related, - BaseObjectViewSetMixin + BaseObjectViewSetMixin, ) from ralph.assets.models import ( ConfigurationClass, ConfigurationModule, Ethernet, - ServiceEnvironment + ServiceEnvironment, ) from ralph.data_center.admin import DataCenterAssetAdmin from ralph.data_center.api.serializers import ( @@ -27,7 +27,7 @@ RackAccessorySerializer, RackSerializer, ServerRoomSerializer, - VIPSerializer + VIPSerializer, ) from ralph.data_center.models import ( Accessory, @@ -40,7 +40,7 @@ Rack, RackAccessory, ServerRoom, - VIP + VIP, ) from ralph.virtual.models import CloudHost, VirtualServer @@ -55,59 +55,55 @@ class DataCenterAssetViewSet(BaseObjectViewSetMixin, RalphAPIViewSet): serializer_class = DataCenterAssetSerializer save_serializer_class = DataCenterAssetSaveSerializer select_related = DataCenterAssetAdmin.list_select_related + [ - 'rack__server_room__data_center', - 'property_of', 'budget_info', 'content_type', - 'configuration_path__module', - 'securityscan', - 'baseobject_ptr', - 'asset_ptr', + "rack__server_room__data_center", + "property_of", + "budget_info", + "content_type", + "configuration_path__module", + "securityscan", + "baseobject_ptr", + "asset_ptr", ] prefetch_related = base_object_descendant_prefetch_related + [ Prefetch( - 'children', - queryset=VirtualServer.objects.select_related('parent'), - to_attr='virtual_servers' + "children", + queryset=VirtualServer.objects.select_related("parent"), + to_attr="virtual_servers", ), Prefetch( - 'children', - queryset=DataCenterAsset.objects.select_related('parent'), - to_attr='physical_servers' + "children", + queryset=DataCenterAsset.objects.select_related("parent"), + to_attr="physical_servers", ), - 'rack__server_room__data_center', - 'connections', - 'tags', - 'memory_set', + "rack__server_room__data_center", + "connections", + "tags", + "memory_set", Prefetch( - 'cloudhost_set', - queryset=CloudHost.objects.select_related('parent'), - to_attr='cloud_hosts' + "cloudhost_set", + queryset=CloudHost.objects.select_related("parent"), + to_attr="cloud_hosts", ), - Prefetch( - 'ethernet_set', - queryset=Ethernet.objects.select_related('ipaddress') - ), - 'fibrechannelcard_set', - 'processor_set', - 'disk_set', + Prefetch("ethernet_set", queryset=Ethernet.objects.select_related("ipaddress")), + "fibrechannelcard_set", + "processor_set", + "disk_set", ] filter_fields = [ - 'service_env__service__uid', - 'service_env__service__name', - 'service_env__service__id', - 'service_env__environment__name', - 'firmware_version', - 'bios_version', + "service_env__service__uid", + "service_env__service__name", + "service_env__service__id", + "service_env__environment__name", + "firmware_version", + "bios_version", ] additional_filter_class = DataCenterAssetFilterSet - exclude_filter_fields = ['configuration_path'] + exclude_filter_fields = ["configuration_path"] def get_queryset(self): # precache content types, this can save 3 db queries occasionally ContentType.objects.get_for_models( - DataCenterAsset, - ConfigurationClass, - ConfigurationModule, - ServiceEnvironment + DataCenterAsset, ConfigurationClass, ConfigurationModule, ServiceEnvironment ) qs = super().get_queryset() return qs @@ -126,7 +122,7 @@ class RackAccessoryViewSet(RalphAPIViewSet): class RackViewSet(RalphAPIViewSet): queryset = Rack.objects.all() serializer_class = RackSerializer - prefetch_related = ['rackaccessory_set', 'rackaccessory_set__accessory'] + prefetch_related = ["rackaccessory_set", "rackaccessory_set__accessory"] class ServerRoomViewSet(RalphAPIViewSet): @@ -143,8 +139,12 @@ class DatabaseViewSet(RalphAPIViewSet): queryset = Database.objects.all() serializer_class = DatabaseSerializer prefetch_related = ( - 'tags', 'licences', 'custom_fields', 'content_type', - 'service_env__service', 'service_env__environment' + "tags", + "licences", + "custom_fields", + "content_type", + "service_env__service", + "service_env__environment", ) @@ -173,14 +173,17 @@ class ClusterViewSet(BaseObjectViewSetMixin, RalphAPIViewSet): queryset = Cluster.objects.all() serializer_class = ClusterSerializer select_related = [ - 'type', 'parent', 'service_env', 'service_env__service', - 'service_env__environment', 'configuration_path__module', 'content_type' + "type", + "parent", + "service_env", + "service_env__service", + "service_env__environment", + "configuration_path__module", + "content_type", ] prefetch_related = base_object_descendant_prefetch_related + [ - 'tags', 'baseobjectcluster_set__base_object', - Prefetch( - 'ethernet_set', - queryset=Ethernet.objects.select_related('ipaddress') - ), + "tags", + "baseobjectcluster_set__base_object", + Prefetch("ethernet_set", queryset=Ethernet.objects.select_related("ipaddress")), ] additional_filter_class = ClusterFilterSet diff --git a/src/ralph/data_center/apps.py b/src/ralph/data_center/apps.py index 09c55e41ae..7b8c65f7d1 100644 --- a/src/ralph/data_center/apps.py +++ b/src/ralph/data_center/apps.py @@ -3,10 +3,9 @@ class DataCenterConfig(RalphAppConfig): - - name = 'ralph.data_center' + name = "ralph.data_center" def get_load_modules_when_ready(self): if settings.ENABLE_HERMES_INTEGRATION: - return ['publishers', 'subscribers'] + return ["publishers", "subscribers"] return [] diff --git a/src/ralph/data_center/forms.py b/src/ralph/data_center/forms.py index f205e43c8d..8855e8b76f 100644 --- a/src/ralph/data_center/forms.py +++ b/src/ralph/data_center/forms.py @@ -13,10 +13,10 @@ class DataCenterAssetForm(PriceFormMixin, AssetFormMixin, RalphAdminForm): MODEL_TYPE = ObjectModelType.data_center - management_ip = forms.GenericIPAddressField(required=False, protocol='IPv4') + management_ip = forms.GenericIPAddressField(required=False, protocol="IPv4") management_hostname = CharFormFieldWithAutoStrip(required=False) - ip_fields = ['management_ip', 'management_hostname'] + ip_fields = ["management_ip", "management_hostname"] class Meta: model = DataCenterAsset @@ -35,23 +35,21 @@ def save(self, *args, **kwargs): obj.save() if ( - not self.cleaned_data['management_hostname'] and - not self.cleaned_data['management_ip'] + not self.cleaned_data["management_hostname"] + and not self.cleaned_data["management_ip"] ): del obj.management_ip else: - obj.management_ip = self.cleaned_data['management_ip'] - obj.management_hostname = ( - self.cleaned_data['management_hostname'] - ) + obj.management_ip = self.cleaned_data["management_ip"] + obj.management_hostname = self.cleaned_data["management_hostname"] return obj def _validate_mgmt_ip_is_unique(self): - if not self.cleaned_data.get('management_ip'): + if not self.cleaned_data.get("management_ip"): return try: ip = IPAddress.objects.get( - address=self.cleaned_data['management_ip'], + address=self.cleaned_data["management_ip"], ) except IPAddress.DoesNotExist: pass @@ -59,50 +57,49 @@ def _validate_mgmt_ip_is_unique(self): if ip.base_object and ip.base_object.pk != self.instance.pk: ip_obj = ip.base_object.last_descendant msg = _( - 'Management IP is already assigned to ' + "Management IP is already assigned to " '{}' - ).format( - ip_obj.get_absolute_url(), ip_obj - ) - exc = ValidationError({'management_ip': mark_safe(msg)}) + ).format(ip_obj.get_absolute_url(), ip_obj) + exc = ValidationError({"management_ip": mark_safe(msg)}) self._update_errors(exc) def _validate_mgmt_hostname_is_unique(self): # hostname is not unique so this query could return 0, 1 or more # records - if not self.cleaned_data.get('management_hostname'): + if not self.cleaned_data.get("management_hostname"): return hostname_msg = None ips = IPAddress.objects.filter( - hostname=self.cleaned_data['management_hostname'], + hostname=self.cleaned_data["management_hostname"], ) if len(ips) > 1: - hostname_msg = _('Management hostname is already used') + hostname_msg = _("Management hostname is already used") elif len(ips) == 1: ip = ips[0] if ip.base_object and ip.base_object.pk != self.instance.pk: hostname_obj = ip.base_object.last_descendant hostname_msg = _( - 'Management hostname is already assigned to ' + "Management hostname is already assigned to " '{}' - ).format( - hostname_obj.get_absolute_url(), hostname_obj - ) + ).format(hostname_obj.get_absolute_url(), hostname_obj) if hostname_msg: - exc = ValidationError( - {'management_hostname': mark_safe(hostname_msg)} - ) + exc = ValidationError({"management_hostname": mark_safe(hostname_msg)}) self._update_errors(exc) def _clean_mgmt_ip_mgmt_hostname(self): - if ( - self.cleaned_data.get('management_hostname') and - not self.cleaned_data.get('management_ip') + if self.cleaned_data.get("management_hostname") and not self.cleaned_data.get( + "management_ip" ): - self._update_errors(ValidationError({'management_ip': _( - 'Management IP could not be empty when management hostname is ' - 'passed' - )})) + self._update_errors( + ValidationError( + { + "management_ip": _( + "Management IP could not be empty when management hostname is " + "passed" + ) + } + ) + ) def clean(self): super().clean() diff --git a/src/ralph/data_center/migrations/0001_initial.py b/src/ralph/data_center/migrations/0001_initial.py index ad3a330575..e58dee67b3 100644 --- a/src/ralph/data_center/migrations/0001_initial.py +++ b/src/ralph/data_center/migrations/0001_initial.py @@ -12,339 +12,989 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0001_initial'), + ("assets", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Accessory', + name="Accessory", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'verbose_name': 'accessory', - 'verbose_name_plural': 'accessories', + "verbose_name": "accessory", + "verbose_name_plural": "accessories", }, ), migrations.CreateModel( - name='CloudProject', + name="CloudProject", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.CreateModel( - name='Connection', + name="Connection", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('connection_type', models.PositiveIntegerField(verbose_name='connection type', choices=[(1, 'network connection')])), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "connection_type", + models.PositiveIntegerField( + verbose_name="connection type", + choices=[(1, "network connection")], + ), + ), ], ), migrations.CreateModel( - name='Database', + name="Database", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'database', - 'verbose_name_plural': 'databases', + "verbose_name": "database", + "verbose_name_plural": "databases", }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.CreateModel( - name='DataCenter', + name="DataCenter", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('visualization_cols_num', models.PositiveIntegerField(verbose_name='visualization grid columns number', default=20)), - ('visualization_rows_num', models.PositiveIntegerField(verbose_name='visualization grid rows number', default=20)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "visualization_cols_num", + models.PositiveIntegerField( + verbose_name="visualization grid columns number", default=20 + ), + ), + ( + "visualization_rows_num", + models.PositiveIntegerField( + verbose_name="visualization grid rows number", default=20 + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='DataCenterAsset', + name="DataCenterAsset", fields=[ - ('asset_ptr', models.OneToOneField(primary_key=True, to='assets.Asset', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), - ('status', ralph.lib.transitions.fields.TransitionField(choices=[(1, 'new'), (2, 'in use'), (3, 'free'), (4, 'damaged'), (5, 'liquidated'), (6, 'to deploy')], default=1)), - ('position', models.IntegerField(null=True)), - ('orientation', models.PositiveIntegerField(choices=[(1, 'front'), (2, 'back'), (3, 'middle'), (101, 'left'), (102, 'right')], default=1)), - ('slot_no', models.CharField(max_length=3, verbose_name='slot number', blank=True, validators=[django.core.validators.RegexValidator(code='invalid_slot_no', message="Slot number should be a number from range 1-16 with an optional postfix 'A' or 'B' (e.g. '16A')", regex=re.compile('^([1-9][A,B]?|1[0-6][A,B]?)$', 32))], null=True, help_text='Fill it if asset is blade server')), - ('source', models.PositiveIntegerField(verbose_name='source', choices=[(1, 'shipment'), (2, 'salvaged')], blank=True, db_index=True, null=True)), - ('delivery_date', models.DateField(blank=True, null=True)), - ('production_year', models.PositiveSmallIntegerField(blank=True, null=True)), - ('production_use_date', models.DateField(blank=True, null=True)), - ('management_ip', models.GenericIPAddressField(default=None, unique=True, verbose_name='Management IP address', blank=True, null=True, help_text='Presented as string.')), - ('management_hostname', ralph.lib.mixins.fields.NullableCharField(blank=True, null=True, unique=True, max_length=100)), - ('connections', models.ManyToManyField(through='data_center.Connection', to='data_center.DataCenterAsset')), + ( + "asset_ptr", + models.OneToOneField( + primary_key=True, + to="assets.Asset", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "status", + ralph.lib.transitions.fields.TransitionField( + choices=[ + (1, "new"), + (2, "in use"), + (3, "free"), + (4, "damaged"), + (5, "liquidated"), + (6, "to deploy"), + ], + default=1, + ), + ), + ("position", models.IntegerField(null=True)), + ( + "orientation", + models.PositiveIntegerField( + choices=[ + (1, "front"), + (2, "back"), + (3, "middle"), + (101, "left"), + (102, "right"), + ], + default=1, + ), + ), + ( + "slot_no", + models.CharField( + max_length=3, + verbose_name="slot number", + blank=True, + validators=[ + django.core.validators.RegexValidator( + code="invalid_slot_no", + message="Slot number should be a number from range 1-16 with an optional postfix 'A' or 'B' (e.g. '16A')", + regex=re.compile("^([1-9][A,B]?|1[0-6][A,B]?)$", 32), + ) + ], + null=True, + help_text="Fill it if asset is blade server", + ), + ), + ( + "source", + models.PositiveIntegerField( + verbose_name="source", + choices=[(1, "shipment"), (2, "salvaged")], + blank=True, + db_index=True, + null=True, + ), + ), + ("delivery_date", models.DateField(blank=True, null=True)), + ( + "production_year", + models.PositiveSmallIntegerField(blank=True, null=True), + ), + ("production_use_date", models.DateField(blank=True, null=True)), + ( + "management_ip", + models.GenericIPAddressField( + default=None, + unique=True, + verbose_name="Management IP address", + blank=True, + null=True, + help_text="Presented as string.", + ), + ), + ( + "management_hostname", + ralph.lib.mixins.fields.NullableCharField( + blank=True, null=True, unique=True, max_length=100 + ), + ), + ( + "connections", + models.ManyToManyField( + through="data_center.Connection", + to="data_center.DataCenterAsset", + ), + ), ], options={ - 'verbose_name': 'data center asset', - 'verbose_name_plural': 'data center assets', + "verbose_name": "data center asset", + "verbose_name_plural": "data center assets", }, - bases=('assets.asset',), + bases=("assets.asset",), ), migrations.CreateModel( - name='DiscoveryQueue', + name="DiscoveryQueue", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'verbose_name': 'discovery queue', - 'verbose_name_plural': 'discovery queues', - 'ordering': ('name',), + "verbose_name": "discovery queue", + "verbose_name_plural": "discovery queues", + "ordering": ("name",), }, ), migrations.CreateModel( - name='DiskShare', + name="DiskShare", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('share_id', models.PositiveIntegerField(verbose_name='share identifier', blank=True, null=True)), - ('label', models.CharField(verbose_name='name', blank=True, default=None, null=True, max_length=255)), - ('size', models.PositiveIntegerField(verbose_name='size (MiB)', blank=True, null=True)), - ('snapshot_size', models.PositiveIntegerField(verbose_name='size for snapshots (MiB)', blank=True, null=True)), - ('wwn', ralph.lib.mixins.fields.NullableCharField(verbose_name='Volume serial', unique=True, max_length=33)), - ('full', models.BooleanField(default=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "share_id", + models.PositiveIntegerField( + verbose_name="share identifier", blank=True, null=True + ), + ), + ( + "label", + models.CharField( + verbose_name="name", + blank=True, + default=None, + null=True, + max_length=255, + ), + ), + ( + "size", + models.PositiveIntegerField( + verbose_name="size (MiB)", blank=True, null=True + ), + ), + ( + "snapshot_size", + models.PositiveIntegerField( + verbose_name="size for snapshots (MiB)", blank=True, null=True + ), + ), + ( + "wwn", + ralph.lib.mixins.fields.NullableCharField( + verbose_name="Volume serial", unique=True, max_length=33 + ), + ), + ("full", models.BooleanField(default=True)), ], options={ - 'verbose_name': 'disk share', - 'verbose_name_plural': 'disk shares', + "verbose_name": "disk share", + "verbose_name_plural": "disk shares", }, ), migrations.CreateModel( - name='DiskShareMount', + name="DiskShareMount", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('volume', models.CharField(verbose_name='volume', blank=True, default=None, null=True, max_length=255)), - ('size', models.PositiveIntegerField(verbose_name='size (MiB)', blank=True, null=True)), - ('asset', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, default=None, verbose_name='asset', to='assets.Asset', blank=True, null=True)), - ('share', models.ForeignKey(verbose_name='share', to='data_center.DiskShare', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "volume", + models.CharField( + verbose_name="volume", + blank=True, + default=None, + null=True, + max_length=255, + ), + ), + ( + "size", + models.PositiveIntegerField( + verbose_name="size (MiB)", blank=True, null=True + ), + ), + ( + "asset", + models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + default=None, + verbose_name="asset", + to="assets.Asset", + blank=True, + null=True, + ), + ), + ( + "share", + models.ForeignKey( + verbose_name="share", + to="data_center.DiskShare", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'disk share mount', - 'verbose_name_plural': 'disk share mounts', + "verbose_name": "disk share mount", + "verbose_name_plural": "disk share mounts", }, ), migrations.CreateModel( - name='IPAddress', + name="IPAddress", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('last_seen', models.DateTimeField(verbose_name='last seen', auto_now_add=True)), - ('address', models.GenericIPAddressField(default=None, unique=True, verbose_name='IP address', help_text='Presented as string.', null=True)), - ('hostname', models.CharField(verbose_name='Hostname', blank=True, default=None, null=True, max_length=255)), - ('number', models.BigIntegerField(verbose_name='IP address', editable=False, help_text='Presented as int.', unique=True)), - ('is_management', models.BooleanField(verbose_name='This is a management address', default=False)), - ('is_public', models.BooleanField(verbose_name='This is a public address', editable=False, default=False)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ( + "last_seen", + models.DateTimeField(verbose_name="last seen", auto_now_add=True), + ), + ( + "address", + models.GenericIPAddressField( + default=None, + unique=True, + verbose_name="IP address", + help_text="Presented as string.", + null=True, + ), + ), + ( + "hostname", + models.CharField( + verbose_name="Hostname", + blank=True, + default=None, + null=True, + max_length=255, + ), + ), + ( + "number", + models.BigIntegerField( + verbose_name="IP address", + editable=False, + help_text="Presented as int.", + unique=True, + ), + ), + ( + "is_management", + models.BooleanField( + verbose_name="This is a management address", default=False + ), + ), + ( + "is_public", + models.BooleanField( + verbose_name="This is a public address", + editable=False, + default=False, + ), + ), ], options={ - 'verbose_name': 'IP address', - 'verbose_name_plural': 'IP addresses', + "verbose_name": "IP address", + "verbose_name_plural": "IP addresses", }, ), migrations.CreateModel( - name='Network', + name="Network", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('address', models.CharField(verbose_name='network address', help_text='Presented as string (e.g. 192.168.0.0/24)', validators=[ralph.networks.fields.network_validator], unique=True, max_length=18)), - ('gateway', models.GenericIPAddressField(default=None, verbose_name='gateway address', blank=True, null=True, help_text='Presented as string.')), - ('gateway_as_int', models.BigIntegerField(verbose_name='gateway as int', editable=False, blank=True, default=None, null=True)), - ('reserved', models.PositiveIntegerField(verbose_name='reserved', help_text='Number of addresses to be omitted in the automatic determination process, counted from the first in range.', default=10)), - ('reserved_top_margin', models.PositiveIntegerField(verbose_name='reserved (top margin)', help_text='Number of addresses to be omitted in the automatic determination process, counted from the last in range.', default=0)), - ('remarks', models.TextField(verbose_name='remarks', blank=True, default='', help_text='Additional information.')), - ('vlan', models.PositiveIntegerField(verbose_name='VLAN number', blank=True, default=None, null=True)), - ('min_ip', models.BigIntegerField(verbose_name='smallest IP number', editable=False, blank=True, default=None, null=True)), - ('max_ip', models.BigIntegerField(verbose_name='largest IP number', editable=False, blank=True, default=None, null=True)), - ('ignore_addresses', models.BooleanField(verbose_name='Ignore addresses from this network', default=False, help_text='Addresses from this network should never be assigned to any device, because they are not unique.')), - ('dhcp_broadcast', models.BooleanField(verbose_name='Broadcast in DHCP configuration', default=False, db_index=True)), - ('dhcp_config', models.TextField(verbose_name='DHCP additional configuration', blank=True, default='')), - ('data_center', models.ForeignKey(verbose_name='data center', to='data_center.DataCenter', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ( + "address", + models.CharField( + verbose_name="network address", + help_text="Presented as string (e.g. 192.168.0.0/24)", + validators=[ralph.networks.fields.network_validator], + unique=True, + max_length=18, + ), + ), + ( + "gateway", + models.GenericIPAddressField( + default=None, + verbose_name="gateway address", + blank=True, + null=True, + help_text="Presented as string.", + ), + ), + ( + "gateway_as_int", + models.BigIntegerField( + verbose_name="gateway as int", + editable=False, + blank=True, + default=None, + null=True, + ), + ), + ( + "reserved", + models.PositiveIntegerField( + verbose_name="reserved", + help_text="Number of addresses to be omitted in the automatic determination process, counted from the first in range.", + default=10, + ), + ), + ( + "reserved_top_margin", + models.PositiveIntegerField( + verbose_name="reserved (top margin)", + help_text="Number of addresses to be omitted in the automatic determination process, counted from the last in range.", + default=0, + ), + ), + ( + "remarks", + models.TextField( + verbose_name="remarks", + blank=True, + default="", + help_text="Additional information.", + ), + ), + ( + "vlan", + models.PositiveIntegerField( + verbose_name="VLAN number", blank=True, default=None, null=True + ), + ), + ( + "min_ip", + models.BigIntegerField( + verbose_name="smallest IP number", + editable=False, + blank=True, + default=None, + null=True, + ), + ), + ( + "max_ip", + models.BigIntegerField( + verbose_name="largest IP number", + editable=False, + blank=True, + default=None, + null=True, + ), + ), + ( + "ignore_addresses", + models.BooleanField( + verbose_name="Ignore addresses from this network", + default=False, + help_text="Addresses from this network should never be assigned to any device, because they are not unique.", + ), + ), + ( + "dhcp_broadcast", + models.BooleanField( + verbose_name="Broadcast in DHCP configuration", + default=False, + db_index=True, + ), + ), + ( + "dhcp_config", + models.TextField( + verbose_name="DHCP additional configuration", + blank=True, + default="", + ), + ), + ( + "data_center", + models.ForeignKey( + verbose_name="data center", + to="data_center.DataCenter", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'network', - 'verbose_name_plural': 'networks', - 'ordering': ('vlan',), + "verbose_name": "network", + "verbose_name_plural": "networks", + "ordering": ("vlan",), }, ), migrations.CreateModel( - name='NetworkEnvironment', + name="NetworkEnvironment", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('hosts_naming_template', models.CharField(verbose_name='hosts naming template', help_text='E.g. h<200,299>.dc|h<400,499>.dc will produce: h200.dc h201.dc ... h299.dc h400.dc h401.dc', max_length=30)), - ('next_server', models.CharField(verbose_name='next server', blank=True, default='', help_text='The address for a TFTP server for DHCP.', max_length=32)), - ('domain', models.CharField(verbose_name='domain', blank=True, null=True, max_length=255)), - ('remarks', models.TextField(verbose_name='remarks', blank=True, null=True, help_text='Additional information.')), - ('data_center', models.ForeignKey(verbose_name='data center', to='data_center.DataCenter', on_delete=django.db.models.deletion.CASCADE)), - ('queue', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='discovery queue', to='data_center.DiscoveryQueue', blank=True, null=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "hosts_naming_template", + models.CharField( + verbose_name="hosts naming template", + help_text="E.g. h<200,299>.dc|h<400,499>.dc will produce: h200.dc h201.dc ... h299.dc h400.dc h401.dc", + max_length=30, + ), + ), + ( + "next_server", + models.CharField( + verbose_name="next server", + blank=True, + default="", + help_text="The address for a TFTP server for DHCP.", + max_length=32, + ), + ), + ( + "domain", + models.CharField( + verbose_name="domain", blank=True, null=True, max_length=255 + ), + ), + ( + "remarks", + models.TextField( + verbose_name="remarks", + blank=True, + null=True, + help_text="Additional information.", + ), + ), + ( + "data_center", + models.ForeignKey( + verbose_name="data center", + to="data_center.DataCenter", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "queue", + models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + verbose_name="discovery queue", + to="data_center.DiscoveryQueue", + blank=True, + null=True, + ), + ), ], options={ - 'ordering': ('name',), + "ordering": ("name",), }, ), migrations.CreateModel( - name='NetworkKind', + name="NetworkKind", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'verbose_name': 'network kind', - 'verbose_name_plural': 'network kinds', - 'ordering': ('name',), + "verbose_name": "network kind", + "verbose_name_plural": "network kinds", + "ordering": ("name",), }, ), migrations.CreateModel( - name='NetworkTerminator', + name="NetworkTerminator", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'verbose_name': 'network terminator', - 'verbose_name_plural': 'network terminators', - 'ordering': ('name',), + "verbose_name": "network terminator", + "verbose_name_plural": "network terminators", + "ordering": ("name",), }, ), migrations.CreateModel( - name='Rack', + name="Rack", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', max_length=75)), - ('description', models.CharField(verbose_name='description', blank=True, max_length=250)), - ('orientation', models.PositiveIntegerField(choices=[(1, 'top'), (2, 'bottom'), (3, 'left'), (4, 'right')], default=1)), - ('max_u_height', models.IntegerField(default=48)), - ('visualization_col', models.PositiveIntegerField(verbose_name='column number on visualization grid', default=0)), - ('visualization_row', models.PositiveIntegerField(verbose_name='row number on visualization grid', default=0)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("name", models.CharField(verbose_name="name", max_length=75)), + ( + "description", + models.CharField( + verbose_name="description", blank=True, max_length=250 + ), + ), + ( + "orientation", + models.PositiveIntegerField( + choices=[(1, "top"), (2, "bottom"), (3, "left"), (4, "right")], + default=1, + ), + ), + ("max_u_height", models.IntegerField(default=48)), + ( + "visualization_col", + models.PositiveIntegerField( + verbose_name="column number on visualization grid", default=0 + ), + ), + ( + "visualization_row", + models.PositiveIntegerField( + verbose_name="row number on visualization grid", default=0 + ), + ), ], bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='RackAccessory', + name="RackAccessory", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('orientation', models.PositiveIntegerField(choices=[(1, 'front'), (2, 'back'), (3, 'middle'), (101, 'left'), (102, 'right')], default=1)), - ('position', models.IntegerField(null=True)), - ('remarks', models.CharField(verbose_name='Additional remarks', blank=True, max_length=1024)), - ('accessory', models.ForeignKey(to='data_center.Accessory', on_delete=django.db.models.deletion.CASCADE)), - ('rack', models.ForeignKey(to='data_center.Rack', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "orientation", + models.PositiveIntegerField( + choices=[ + (1, "front"), + (2, "back"), + (3, "middle"), + (101, "left"), + (102, "right"), + ], + default=1, + ), + ), + ("position", models.IntegerField(null=True)), + ( + "remarks", + models.CharField( + verbose_name="Additional remarks", blank=True, max_length=1024 + ), + ), + ( + "accessory", + models.ForeignKey( + to="data_center.Accessory", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "rack", + models.ForeignKey( + to="data_center.Rack", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name_plural': 'rack accessories', + "verbose_name_plural": "rack accessories", }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='ServerRoom', + name="ServerRoom", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', max_length=75)), - ('data_center', models.ForeignKey(verbose_name='data center', to='data_center.DataCenter', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("name", models.CharField(verbose_name="name", max_length=75)), + ( + "data_center", + models.ForeignKey( + verbose_name="data center", + to="data_center.DataCenter", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='VIP', + name="VIP", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'VIP', - 'verbose_name_plural': 'VIPs', + "verbose_name": "VIP", + "verbose_name_plural": "VIPs", }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.CreateModel( - name='VirtualServer', + name="VirtualServer", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Virtual server (VM)', - 'verbose_name_plural': 'Virtual servers (VM)', + "verbose_name": "Virtual server (VM)", + "verbose_name_plural": "Virtual servers (VM)", }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.AddField( - model_name='rack', - name='accessories', - field=models.ManyToManyField(through='data_center.RackAccessory', to='data_center.Accessory'), + model_name="rack", + name="accessories", + field=models.ManyToManyField( + through="data_center.RackAccessory", to="data_center.Accessory" + ), ), migrations.AddField( - model_name='rack', - name='server_room', - field=models.ForeignKey(verbose_name='server room', to='data_center.ServerRoom', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="rack", + name="server_room", + field=models.ForeignKey( + verbose_name="server room", + to="data_center.ServerRoom", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='network', - name='kind', - field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, default=None, verbose_name='network kind', to='data_center.NetworkKind', blank=True, null=True), + model_name="network", + name="kind", + field=models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + default=None, + verbose_name="network kind", + to="data_center.NetworkKind", + blank=True, + null=True, + ), ), migrations.AddField( - model_name='network', - name='network_environment', - field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='environment', to='data_center.NetworkEnvironment', blank=True, null=True), + model_name="network", + name="network_environment", + field=models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + verbose_name="environment", + to="data_center.NetworkEnvironment", + blank=True, + null=True, + ), ), migrations.AddField( - model_name='network', - name='racks', - field=models.ManyToManyField(verbose_name='racks', blank=True, to='data_center.Rack'), + model_name="network", + name="racks", + field=models.ManyToManyField( + verbose_name="racks", blank=True, to="data_center.Rack" + ), ), migrations.AddField( - model_name='network', - name='terminators', - field=models.ManyToManyField(verbose_name='network terminators', to='data_center.NetworkTerminator'), + model_name="network", + name="terminators", + field=models.ManyToManyField( + verbose_name="network terminators", to="data_center.NetworkTerminator" + ), ), migrations.AddField( - model_name='ipaddress', - name='base_object', - field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, default=None, verbose_name='Base object', to='assets.BaseObject', blank=True, null=True), + model_name="ipaddress", + name="base_object", + field=models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + default=None, + verbose_name="Base object", + to="assets.BaseObject", + blank=True, + null=True, + ), ), migrations.AddField( - model_name='diskshare', - name='base_object', - field=models.ForeignKey(to='assets.BaseObject', related_name='diskshare', on_delete=django.db.models.deletion.CASCADE), + model_name="diskshare", + name="base_object", + field=models.ForeignKey( + to="assets.BaseObject", + related_name="diskshare", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='diskshare', - name='model', - field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, default=None, verbose_name='model', to='assets.ComponentModel', blank=True, null=True), + model_name="diskshare", + name="model", + field=models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + default=None, + verbose_name="model", + to="assets.ComponentModel", + blank=True, + null=True, + ), ), migrations.AddField( - model_name='datacenterasset', - name='rack', - field=models.ForeignKey(to='data_center.Rack', null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="datacenterasset", + name="rack", + field=models.ForeignKey( + to="data_center.Rack", + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='connection', - name='inbound', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='connected device', to='data_center.DataCenterAsset', related_name='inbound_connections'), + model_name="connection", + name="inbound", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + verbose_name="connected device", + to="data_center.DataCenterAsset", + related_name="inbound_connections", + ), ), migrations.AddField( - model_name='connection', - name='outbound', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='connected to device', to='data_center.DataCenterAsset', related_name='outbound_connections'), + model_name="connection", + name="outbound", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + verbose_name="connected to device", + to="data_center.DataCenterAsset", + related_name="outbound_connections", + ), ), migrations.AlterUniqueTogether( - name='rack', - unique_together=set([('name', 'server_room')]), + name="rack", + unique_together=set([("name", "server_room")]), ), migrations.AlterUniqueTogether( - name='disksharemount', - unique_together=set([('share', 'asset')]), + name="disksharemount", + unique_together=set([("share", "asset")]), ), ] diff --git a/src/ralph/data_center/migrations/0002_auto_20151125_1354.py b/src/ralph/data_center/migrations/0002_auto_20151125_1354.py index b94f7b2e2b..318b4139ae 100644 --- a/src/ralph/data_center/migrations/0002_auto_20151125_1354.py +++ b/src/ralph/data_center/migrations/0002_auto_20151125_1354.py @@ -5,30 +5,29 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0001_initial'), + ("data_center", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='ipaddress', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="ipaddress", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='ipaddress', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="ipaddress", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='network', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="network", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='network', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="network", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), ] diff --git a/src/ralph/data_center/migrations/0003_auto_20151126_2222.py b/src/ralph/data_center/migrations/0003_auto_20151126_2222.py index 83a2bce173..90856c5863 100644 --- a/src/ralph/data_center/migrations/0003_auto_20151126_2222.py +++ b/src/ralph/data_center/migrations/0003_auto_20151126_2222.py @@ -7,25 +7,36 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0002_auto_20151125_1354'), + ("data_center", "0002_auto_20151125_1354"), ] operations = [ migrations.AlterField( - model_name='datacenterasset', - name='management_ip', - field=ralph.lib.mixins.fields.NullableGenericIPAddressField(blank=True, null=True, unique=True, default=None, help_text='Presented as string.', verbose_name='Management IP address'), + model_name="datacenterasset", + name="management_ip", + field=ralph.lib.mixins.fields.NullableGenericIPAddressField( + blank=True, + null=True, + unique=True, + default=None, + help_text="Presented as string.", + verbose_name="Management IP address", + ), ), migrations.AlterField( - model_name='datacenterasset', - name='position', + model_name="datacenterasset", + name="position", field=models.IntegerField(null=True, blank=True), ), migrations.AlterField( - model_name='datacenterasset', - name='rack', - field=models.ForeignKey(null=True, to='data_center.Rack', blank=True, on_delete=django.db.models.deletion.CASCADE), + model_name="datacenterasset", + name="rack", + field=models.ForeignKey( + null=True, + to="data_center.Rack", + blank=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/data_center/migrations/0004_auto_20151204_0758.py b/src/ralph/data_center/migrations/0004_auto_20151204_0758.py index 4fa9e1266d..85df4990b4 100644 --- a/src/ralph/data_center/migrations/0004_auto_20151204_0758.py +++ b/src/ralph/data_center/migrations/0004_auto_20151204_0758.py @@ -1,22 +1,21 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0003_auto_20151126_2222'), + ("data_center", "0003_auto_20151126_2222"), ] operations = [ migrations.AlterModelOptions( - name='datacenter', - options={'ordering': ['name']}, + name="datacenter", + options={"ordering": ["name"]}, ), migrations.AlterModelOptions( - name='serverroom', - options={'ordering': ['name']}, + name="serverroom", + options={"ordering": ["name"]}, ), ] diff --git a/src/ralph/data_center/migrations/0005_auto_20160121_1133.py b/src/ralph/data_center/migrations/0005_auto_20160121_1133.py index 07ebf9324c..5ad5082425 100644 --- a/src/ralph/data_center/migrations/0005_auto_20160121_1133.py +++ b/src/ralph/data_center/migrations/0005_auto_20160121_1133.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations from ralph.data_center.models.physical import ACCESSORY_DATA @@ -17,13 +17,10 @@ def unload_initial_accessory(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0004_auto_20151204_0758'), + ("data_center", "0004_auto_20151204_0758"), ] operations = [ - migrations.RunPython( - initial_accessory, reverse_code=unload_initial_accessory - ), + migrations.RunPython(initial_accessory, reverse_code=unload_initial_accessory), ] diff --git a/src/ralph/data_center/migrations/0006_rack_require_position.py b/src/ralph/data_center/migrations/0006_rack_require_position.py index 9ef47f21f4..f6c35c7ba3 100644 --- a/src/ralph/data_center/migrations/0006_rack_require_position.py +++ b/src/ralph/data_center/migrations/0006_rack_require_position.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0005_auto_20160121_1133'), + ("data_center", "0005_auto_20160121_1133"), ] operations = [ migrations.AddField( - model_name='rack', - name='require_position', - field=models.BooleanField(default=True, help_text='Uncheck if position is optional for this rack (ex. when rack has warehouse-kind role'), + model_name="rack", + name="require_position", + field=models.BooleanField( + default=True, + help_text="Uncheck if position is optional for this rack (ex. when rack has warehouse-kind role", + ), ), ] diff --git a/src/ralph/data_center/migrations/0007_auto_20160225_1818.py b/src/ralph/data_center/migrations/0007_auto_20160225_1818.py index 0d3fd2f959..5834003b73 100644 --- a/src/ralph/data_center/migrations/0007_auto_20160225_1818.py +++ b/src/ralph/data_center/migrations/0007_auto_20160225_1818.py @@ -1,32 +1,30 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('supports', '0005_auto_20160105_1222'), - ('assets', '0008_auto_20160122_1429'), - ('licences', '0002_auto_20151204_1325'), - ('data_center', '0006_rack_require_position'), + ("supports", "0005_auto_20160105_1222"), + ("assets", "0008_auto_20160122_1429"), + ("licences", "0002_auto_20151204_1325"), + ("data_center", "0006_rack_require_position"), ] # move models to virtual app database_operations = [ - migrations.AlterModelTable('VirtualServer', 'virtual_virtualserver'), - migrations.AlterModelTable('CloudProject', 'virtual_cloudproject'), + migrations.AlterModelTable("VirtualServer", "virtual_virtualserver"), + migrations.AlterModelTable("CloudProject", "virtual_cloudproject"), ] state_operations = [ - migrations.DeleteModel('VirtualServer'), - migrations.DeleteModel('CloudProject'), + migrations.DeleteModel("VirtualServer"), + migrations.DeleteModel("CloudProject"), ] operations = [ migrations.SeparateDatabaseAndState( - database_operations=database_operations, - state_operations=state_operations + database_operations=database_operations, state_operations=state_operations ) ] diff --git a/src/ralph/data_center/migrations/0008_datacenter_show_on_dashboard.py b/src/ralph/data_center/migrations/0008_datacenter_show_on_dashboard.py index 95be7efb1d..8010a2c97c 100644 --- a/src/ralph/data_center/migrations/0008_datacenter_show_on_dashboard.py +++ b/src/ralph/data_center/migrations/0008_datacenter_show_on_dashboard.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0007_auto_20160225_1818'), + ("data_center", "0007_auto_20160225_1818"), ] operations = [ migrations.AddField( - model_name='datacenter', - name='show_on_dashboard', + model_name="datacenter", + name="show_on_dashboard", field=models.BooleanField(default=True), ), ] diff --git a/src/ralph/data_center/migrations/0009_auto_20160419_1003.py b/src/ralph/data_center/migrations/0009_auto_20160419_1003.py index df856e8658..bfcb28cecd 100644 --- a/src/ralph/data_center/migrations/0009_auto_20160419_1003.py +++ b/src/ralph/data_center/migrations/0009_auto_20160419_1003.py @@ -7,60 +7,108 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0010_auto_20160405_1531'), - ('data_center', '0008_datacenter_show_on_dashboard'), + ("assets", "0010_auto_20160405_1531"), + ("data_center", "0008_datacenter_show_on_dashboard"), ] operations = [ migrations.CreateModel( - name='BaseObjectCluster', + name="BaseObjectCluster", fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), - ('is_master', models.BooleanField(default=False)), + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), + ("is_master", models.BooleanField(default=False)), ], ), migrations.CreateModel( - name='Cluster', + name="Cluster", fields=[ - ('baseobject_ptr', models.OneToOneField(to='assets.BaseObject', parent_link=True, serialize=False, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(verbose_name='name', max_length=255, unique=True)), - ('base_objects', models.ManyToManyField(through='data_center.BaseObjectCluster', to='assets.BaseObject', verbose_name='Assigned base objects', related_name='_cluster_base_objects_+')), + ( + "baseobject_ptr", + models.OneToOneField( + to="assets.BaseObject", + parent_link=True, + serialize=False, + auto_created=True, + primary_key=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "name", + models.CharField(verbose_name="name", max_length=255, unique=True), + ), + ( + "base_objects", + models.ManyToManyField( + through="data_center.BaseObjectCluster", + to="assets.BaseObject", + verbose_name="Assigned base objects", + related_name="_cluster_base_objects_+", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('assets.baseobject', models.Model), + bases=("assets.baseobject", models.Model), ), migrations.CreateModel( - name='ClusterType', + name="ClusterType", fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', max_length=255, unique=True)), + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", max_length=255, unique=True), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, ), migrations.AddField( - model_name='cluster', - name='type', - field=models.ForeignKey(to='data_center.ClusterType', on_delete=django.db.models.deletion.CASCADE), + model_name="cluster", + name="type", + field=models.ForeignKey( + to="data_center.ClusterType", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='baseobjectcluster', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(to='assets.BaseObject', related_name='clusters', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectcluster", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + to="assets.BaseObject", + related_name="clusters", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='baseobjectcluster', - name='cluster', - field=models.ForeignKey(to='data_center.Cluster', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectcluster", + name="cluster", + field=models.ForeignKey( + to="data_center.Cluster", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AlterUniqueTogether( - name='baseobjectcluster', - unique_together=set([('cluster', 'base_object')]), + name="baseobjectcluster", + unique_together=set([("cluster", "base_object")]), ), ] diff --git a/src/ralph/data_center/migrations/0010_visualization_fields_for_serverroom.py b/src/ralph/data_center/migrations/0010_visualization_fields_for_serverroom.py index b70590fb7e..d7a2367de1 100644 --- a/src/ralph/data_center/migrations/0010_visualization_fields_for_serverroom.py +++ b/src/ralph/data_center/migrations/0010_visualization_fields_for_serverroom.py @@ -5,66 +5,59 @@ def migrate_visualization(apps, schema_editor): - DataCenter = apps.get_model('data_center', 'DataCenter') - ServerRoom = apps.get_model('data_center', 'ServerRoom') + DataCenter = apps.get_model("data_center", "DataCenter") + ServerRoom = apps.get_model("data_center", "ServerRoom") data_centers = DataCenter.objects.all() for data_center in data_centers: server_rooms = ServerRoom.objects.filter(data_center__id=data_center.id) for server_room in server_rooms: - server_room.visualization_cols_num = \ - data_center.visualization_cols_num - server_room.visualization_rows_num = \ - data_center.visualization_rows_num + server_room.visualization_cols_num = data_center.visualization_cols_num + server_room.visualization_rows_num = data_center.visualization_rows_num server_room.save() def migrate_visualization_rev(apps, schema_editor): - DataCenter = apps.get_model('data_center', 'DataCenter') - ServerRoom = apps.get_model('data_center', 'ServerRoom') + DataCenter = apps.get_model("data_center", "DataCenter") + ServerRoom = apps.get_model("data_center", "ServerRoom") data_centers = DataCenter.objects.all() print(data_centers.first().visualization_cols_num) for data_center in data_centers: server_room = ServerRoom.objects.filter(data_center__id=data_center.id) if server_room: - data_center.visualization_cols_num = \ - server_room[0].visualization_cols_num - data_center.visualization_rows_num = \ - server_room[0].visualization_rows_num + data_center.visualization_cols_num = server_room[0].visualization_cols_num + data_center.visualization_rows_num = server_room[0].visualization_rows_num data_center.save() class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0009_auto_20160419_1003'), + ("data_center", "0009_auto_20160419_1003"), ] operations = [ migrations.AddField( - model_name='serverroom', - name='visualization_cols_num', + model_name="serverroom", + name="visualization_cols_num", field=models.PositiveIntegerField( - verbose_name='visualization grid columns number', default=20), + verbose_name="visualization grid columns number", default=20 + ), ), migrations.AddField( - model_name='serverroom', - name='visualization_rows_num', + model_name="serverroom", + name="visualization_rows_num", field=models.PositiveIntegerField( - verbose_name='visualization grid rows number', default=20), - ), - migrations.RunPython( - migrate_visualization, - migrate_visualization_rev + verbose_name="visualization grid rows number", default=20 + ), ), + migrations.RunPython(migrate_visualization, migrate_visualization_rev), migrations.RemoveField( - model_name='datacenter', - name='visualization_cols_num', + model_name="datacenter", + name="visualization_cols_num", ), migrations.RemoveField( - model_name='datacenter', - name='visualization_rows_num', + model_name="datacenter", + name="visualization_rows_num", ), - ] diff --git a/src/ralph/data_center/migrations/0011_change_networks_models.py b/src/ralph/data_center/migrations/0011_change_networks_models.py index 014faa42ab..5682512916 100644 --- a/src/ralph/data_center/migrations/0011_change_networks_models.py +++ b/src/ralph/data_center/migrations/0011_change_networks_models.py @@ -8,115 +8,163 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0010_visualization_fields_for_serverroom'), + ("data_center", "0010_visualization_fields_for_serverroom"), ] operations = [ migrations.AlterModelOptions( - name='network', - options={'verbose_name': 'network', 'verbose_name_plural': 'networks'}, + name="network", + options={"verbose_name": "network", "verbose_name_plural": "networks"}, ), migrations.AddField( - model_name='ipaddress', - name='is_gateway', - field=models.BooleanField(default=False, verbose_name='This is a gateway address', editable=False), + model_name="ipaddress", + name="is_gateway", + field=models.BooleanField( + default=False, verbose_name="This is a gateway address", editable=False + ), ), migrations.AddField( - model_name='ipaddress', - name='network', - field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, null=True, default=None, related_name='ips', to='data_center.Network', editable=False), + model_name="ipaddress", + name="network", + field=models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, + null=True, + default=None, + related_name="ips", + to="data_center.Network", + editable=False, + ), ), migrations.AddField( - model_name='ipaddress', - name='status', - field=models.PositiveSmallIntegerField(default=1, choices=[(1, 'DHCP (used)'), (2, 'reserved')]), + model_name="ipaddress", + name="status", + field=models.PositiveSmallIntegerField( + default=1, choices=[(1, "DHCP (used)"), (2, "reserved")] + ), ), migrations.AddField( - model_name='network', - name='level', + model_name="network", + name="level", field=models.PositiveIntegerField(default=0, db_index=True, editable=False), preserve_default=False, ), migrations.AddField( - model_name='network', - name='lft', + model_name="network", + name="lft", field=models.PositiveIntegerField(default=0, db_index=True, editable=False), preserve_default=False, ), migrations.AddField( - model_name='network', - name='parent', - field=mptt.fields.TreeForeignKey(blank=True, null=True, related_name='children', to='data_center.Network', editable=False, on_delete=django.db.models.deletion.CASCADE), + model_name="network", + name="parent", + field=mptt.fields.TreeForeignKey( + blank=True, + null=True, + related_name="children", + to="data_center.Network", + editable=False, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='network', - name='rght', + model_name="network", + name="rght", field=models.PositiveIntegerField(default=0, db_index=True, editable=False), preserve_default=False, ), migrations.AddField( - model_name='network', - name='tree_id', + model_name="network", + name="tree_id", field=models.PositiveIntegerField(default=0, db_index=True, editable=False), preserve_default=False, ), migrations.AlterField( - model_name='ipaddress', - name='number', - field=models.DecimalField(decimal_places=0, help_text='Presented as int.', verbose_name='IP address', default=None, unique=True, editable=False, max_digits=39), + model_name="ipaddress", + name="number", + field=models.DecimalField( + decimal_places=0, + help_text="Presented as int.", + verbose_name="IP address", + default=None, + unique=True, + editable=False, + max_digits=39, + ), ), migrations.AlterField( - model_name='network', - name='address', - field=ralph.networks.fields.IPNetwork(verbose_name='network address', help_text='Presented as string (e.g. 192.168.0.0/24)'), + model_name="network", + name="address", + field=ralph.networks.fields.IPNetwork( + verbose_name="network address", + help_text="Presented as string (e.g. 192.168.0.0/24)", + ), ), migrations.AlterField( - model_name='network', - name='max_ip', - field=models.DecimalField(blank=True, null=True, default=None, verbose_name='largest IP number', decimal_places=0, editable=False, max_digits=39), + model_name="network", + name="max_ip", + field=models.DecimalField( + blank=True, + null=True, + default=None, + verbose_name="largest IP number", + decimal_places=0, + editable=False, + max_digits=39, + ), ), migrations.AlterField( - model_name='network', - name='min_ip', - field=models.DecimalField(blank=True, null=True, default=None, verbose_name='smallest IP number', decimal_places=0, editable=False, max_digits=39), + model_name="network", + name="min_ip", + field=models.DecimalField( + blank=True, + null=True, + default=None, + verbose_name="smallest IP number", + decimal_places=0, + editable=False, + max_digits=39, + ), ), migrations.AlterField( - model_name='network', - name='terminators', - field=models.ManyToManyField(verbose_name='network terminators', blank=True, to='data_center.NetworkTerminator'), + model_name="network", + name="terminators", + field=models.ManyToManyField( + verbose_name="network terminators", + blank=True, + to="data_center.NetworkTerminator", + ), ), migrations.AlterUniqueTogether( - name='network', - unique_together=set([('min_ip', 'max_ip')]), + name="network", + unique_together=set([("min_ip", "max_ip")]), ), migrations.RemoveField( - model_name='network', - name='data_center', + model_name="network", + name="data_center", ), migrations.RemoveField( - model_name='network', - name='dhcp_config', + model_name="network", + name="dhcp_config", ), migrations.RemoveField( - model_name='network', - name='gateway', + model_name="network", + name="gateway", ), migrations.RemoveField( - model_name='network', - name='gateway_as_int', + model_name="network", + name="gateway_as_int", ), migrations.RemoveField( - model_name='network', - name='ignore_addresses', + model_name="network", + name="ignore_addresses", ), migrations.RemoveField( - model_name='network', - name='reserved', + model_name="network", + name="reserved", ), migrations.RemoveField( - model_name='network', - name='reserved_top_margin', + model_name="network", + name="reserved_top_margin", ), ] diff --git a/src/ralph/data_center/migrations/0012_custom_move_to_networks.py b/src/ralph/data_center/migrations/0012_custom_move_to_networks.py index 152489d563..77615645fe 100644 --- a/src/ralph/data_center/migrations/0012_custom_move_to_networks.py +++ b/src/ralph/data_center/migrations/0012_custom_move_to_networks.py @@ -1,38 +1,34 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -import mptt.fields -import ralph.networks.fields -import django.db.models.deletion +from django.db import migrations -class Migration(migrations.Migration): +class Migration(migrations.Migration): dependencies = [ - ('data_center', '0011_change_networks_models'), + ("data_center", "0011_change_networks_models"), ] database_operations = [ - migrations.AlterModelTable('NetworkKind', 'networks_networkkind'), - migrations.AlterModelTable('NetworkEnvironment', 'networks_networkenvironment'), - migrations.AlterModelTable('Network', 'networks_network'), - migrations.AlterModelTable('NetworkTerminator', 'networks_networkterminator'), - migrations.AlterModelTable('DiscoveryQueue', 'networks_discoveryqueue'), - migrations.AlterModelTable('IPAddress', 'networks_ipaddress'), + migrations.AlterModelTable("NetworkKind", "networks_networkkind"), + migrations.AlterModelTable("NetworkEnvironment", "networks_networkenvironment"), + migrations.AlterModelTable("Network", "networks_network"), + migrations.AlterModelTable("NetworkTerminator", "networks_networkterminator"), + migrations.AlterModelTable("DiscoveryQueue", "networks_discoveryqueue"), + migrations.AlterModelTable("IPAddress", "networks_ipaddress"), ] state_operations = [ - migrations.DeleteModel('NetworkKind'), - migrations.DeleteModel('NetworkEnvironment'), - migrations.DeleteModel('Network'), - migrations.DeleteModel('NetworkTerminator'), - migrations.DeleteModel('DiscoveryQueue'), - migrations.DeleteModel('IPAddress'), + migrations.DeleteModel("NetworkKind"), + migrations.DeleteModel("NetworkEnvironment"), + migrations.DeleteModel("Network"), + migrations.DeleteModel("NetworkTerminator"), + migrations.DeleteModel("DiscoveryQueue"), + migrations.DeleteModel("IPAddress"), ] operations = [ migrations.SeparateDatabaseAndState( - database_operations=database_operations, - state_operations=state_operations + database_operations=database_operations, state_operations=state_operations ) ] diff --git a/src/ralph/data_center/migrations/0013_auto_20160606_1438.py b/src/ralph/data_center/migrations/0013_auto_20160606_1438.py index 16ebb2f13b..2a0da28133 100644 --- a/src/ralph/data_center/migrations/0013_auto_20160606_1438.py +++ b/src/ralph/data_center/migrations/0013_auto_20160606_1438.py @@ -8,42 +8,62 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0012_custom_move_to_networks'), + ("data_center", "0012_custom_move_to_networks"), ] operations = [ migrations.AddField( - model_name='cluster', - name='hostname', - field=ralph.lib.mixins.fields.NullableCharField(blank=True, unique=True, max_length=255, null=True, verbose_name='hostname'), + model_name="cluster", + name="hostname", + field=ralph.lib.mixins.fields.NullableCharField( + blank=True, + unique=True, + max_length=255, + null=True, + verbose_name="hostname", + ), ), migrations.AddField( - model_name='cluster', - name='status', - field=ralph.lib.transitions.fields.TransitionField(choices=[(1, 'in use'), (2, 'for deploy')], default=1), + model_name="cluster", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + choices=[(1, "in use"), (2, "for deploy")], default=1 + ), ), migrations.AddField( - model_name='clustertype', - name='show_master_summary', - field=models.BooleanField(help_text='show master information on cluster page, ex. hostname, model, location etc.', default=False), + model_name="clustertype", + name="show_master_summary", + field=models.BooleanField( + help_text="show master information on cluster page, ex. hostname, model, location etc.", + default=False, + ), ), migrations.AddField( - model_name='diskshare', - name='created', - field=models.DateTimeField(default=datetime.datetime(2016, 6, 6, 14, 38, 42, 553494), verbose_name='date created', auto_now_add=True), + model_name="diskshare", + name="created", + field=models.DateTimeField( + default=datetime.datetime(2016, 6, 6, 14, 38, 42, 553494), + verbose_name="date created", + auto_now_add=True, + ), preserve_default=False, ), migrations.AddField( - model_name='diskshare', - name='modified', - field=models.DateTimeField(default=datetime.datetime(2016, 6, 6, 14, 38, 45, 192509), verbose_name='last modified', auto_now=True), + model_name="diskshare", + name="modified", + field=models.DateTimeField( + default=datetime.datetime(2016, 6, 6, 14, 38, 45, 192509), + verbose_name="last modified", + auto_now=True, + ), preserve_default=False, ), migrations.AlterField( - model_name='cluster', - name='name', - field=models.CharField(blank=True, null=True, max_length=255, verbose_name='name'), + model_name="cluster", + name="name", + field=models.CharField( + blank=True, null=True, max_length=255, verbose_name="name" + ), ), ] diff --git a/src/ralph/data_center/migrations/0014_custom_move_managment_to_networks.py b/src/ralph/data_center/migrations/0014_custom_move_managment_to_networks.py index d197e4bc5d..4b3f37f33c 100644 --- a/src/ralph/data_center/migrations/0014_custom_move_managment_to_networks.py +++ b/src/ralph/data_center/migrations/0014_custom_move_managment_to_networks.py @@ -4,12 +4,12 @@ import ipaddress import django -from django.db import migrations, models +from django.db import migrations def move_to_networks(apps, schema_editor): - DataCenterAsset = apps.get_model('data_center', 'DataCenterAsset') - IPAddress = apps.get_model('networks', 'IPAddress') + DataCenterAsset = apps.get_model("data_center", "DataCenterAsset") + IPAddress = apps.get_model("networks", "IPAddress") assets = DataCenterAsset.objects.exclude(management_ip_old=None) for idx, asset in enumerate(assets): try: @@ -28,7 +28,7 @@ def move_to_networks(apps, schema_editor): def move_from_networks(apps, schema_editor): - IPAddress = apps.get_model('networks', 'IPAddress') + IPAddress = apps.get_model("networks", "IPAddress") ips = IPAddress.objects.filter( is_management=True, base_object__asset__datacenterasset__isnull=False ) @@ -40,41 +40,38 @@ def move_from_networks(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0013_auto_20160606_1438'), - ('networks', '0001_initial'), + ("data_center", "0013_auto_20160606_1438"), + ("networks", "0001_initial"), ] operations = [ migrations.AlterModelManagers( - name='datacenterasset', + name="datacenterasset", managers=[ - ('objects', django.db.models.manager.Manager()), + ("objects", django.db.models.manager.Manager()), ], ), # rename first to `management_ip_old` because there is now property # `management_ip` in DataCenterAsset which "hides" database field # thus should not be used directly migrations.RenameField( - model_name='datacenterasset', - old_name='management_ip', - new_name='management_ip_old' + model_name="datacenterasset", + old_name="management_ip", + new_name="management_ip_old", ), migrations.RenameField( - model_name='datacenterasset', - old_name='management_hostname', - new_name='management_hostname_old' - ), - migrations.RunPython( - move_to_networks, reverse_code=move_from_networks + model_name="datacenterasset", + old_name="management_hostname", + new_name="management_hostname_old", ), + migrations.RunPython(move_to_networks, reverse_code=move_from_networks), migrations.RemoveField( - model_name='datacenterasset', - name='management_hostname_old', + model_name="datacenterasset", + name="management_hostname_old", ), migrations.RemoveField( - model_name='datacenterasset', - name='management_ip_old', + model_name="datacenterasset", + name="management_ip_old", ), ] diff --git a/src/ralph/data_center/migrations/0015_auto_20160615_2140.py b/src/ralph/data_center/migrations/0015_auto_20160615_2140.py index 548cb60948..ec7fb43c20 100644 --- a/src/ralph/data_center/migrations/0015_auto_20160615_2140.py +++ b/src/ralph/data_center/migrations/0015_auto_20160615_2140.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0014_custom_move_managment_to_networks'), + ("data_center", "0014_custom_move_managment_to_networks"), ] operations = [ migrations.AlterField( - model_name='diskshare', - name='base_object', - field=models.ForeignKey(related_name='diskshare_set', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE), + model_name="diskshare", + name="base_object", + field=models.ForeignKey( + related_name="diskshare_set", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/data_center/migrations/0016_diskshare_model_name.py b/src/ralph/data_center/migrations/0016_diskshare_model_name.py index c2e1783670..957f912ea3 100644 --- a/src/ralph/data_center/migrations/0016_diskshare_model_name.py +++ b/src/ralph/data_center/migrations/0016_diskshare_model_name.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0015_auto_20160615_2140'), + ("data_center", "0015_auto_20160615_2140"), ] operations = [ migrations.AddField( - model_name='diskshare', - name='model_name', - field=models.CharField(max_length=255, verbose_name='model name', blank=True, null=True), + model_name="diskshare", + name="model_name", + field=models.CharField( + max_length=255, verbose_name="model name", blank=True, null=True + ), ), ] diff --git a/src/ralph/data_center/migrations/0017_auto_20160719_1530.py b/src/ralph/data_center/migrations/0017_auto_20160719_1530.py index 21d855e21a..3bb340087d 100644 --- a/src/ralph/data_center/migrations/0017_auto_20160719_1530.py +++ b/src/ralph/data_center/migrations/0017_auto_20160719_1530.py @@ -5,20 +5,23 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0016_diskshare_model_name'), + ("data_center", "0016_diskshare_model_name"), ] operations = [ migrations.AddField( - model_name='datacenterasset', - name='bios_version', - field=models.CharField(null=True, verbose_name='BIOS version', max_length=256, blank=True), + model_name="datacenterasset", + name="bios_version", + field=models.CharField( + null=True, verbose_name="BIOS version", max_length=256, blank=True + ), ), migrations.AddField( - model_name='datacenterasset', - name='firmware_version', - field=models.CharField(null=True, verbose_name='firmware version', max_length=256, blank=True), + model_name="datacenterasset", + name="firmware_version", + field=models.CharField( + null=True, verbose_name="firmware version", max_length=256, blank=True + ), ), ] diff --git a/src/ralph/data_center/migrations/0018_auto_20160729_1401.py b/src/ralph/data_center/migrations/0018_auto_20160729_1401.py index ec44cc04dd..5f174b1594 100644 --- a/src/ralph/data_center/migrations/0018_auto_20160729_1401.py +++ b/src/ralph/data_center/migrations/0018_auto_20160729_1401.py @@ -6,15 +6,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0017_auto_20160719_1530'), + ("data_center", "0017_auto_20160719_1530"), ] operations = [ migrations.AlterField( - model_name='rack', - name='server_room', - field=models.ForeignKey(verbose_name='server room', null=True, to='data_center.ServerRoom', on_delete=django.db.models.deletion.CASCADE), + model_name="rack", + name="server_room", + field=models.ForeignKey( + verbose_name="server room", + null=True, + to="data_center.ServerRoom", + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/data_center/migrations/0019_dchost.py b/src/ralph/data_center/migrations/0019_dchost.py index d02c9f0897..f72f7117a9 100644 --- a/src/ralph/data_center/migrations/0019_dchost.py +++ b/src/ralph/data_center/migrations/0019_dchost.py @@ -1,24 +1,22 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('assets', '0019_auto_20160719_1443'), - ('data_center', '0018_auto_20160729_1401'), + ("assets", "0019_auto_20160719_1443"), + ("data_center", "0018_auto_20160729_1401"), ] operations = [ migrations.CreateModel( - name='DCHost', - fields=[ - ], + name="DCHost", + fields=[], options={ - 'proxy': True, + "proxy": True, }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), ] diff --git a/src/ralph/data_center/migrations/0020_auto_20160907_1116.py b/src/ralph/data_center/migrations/0020_auto_20160907_1116.py index 34a2fa8b1d..e2ba071d3f 100644 --- a/src/ralph/data_center/migrations/0020_auto_20160907_1116.py +++ b/src/ralph/data_center/migrations/0020_auto_20160907_1116.py @@ -6,37 +6,42 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0009_auto_20160823_0921'), - ('data_center', '0019_dchost'), + ("networks", "0009_auto_20160823_0921"), + ("data_center", "0019_dchost"), ] operations = [ migrations.AddField( - model_name='vip', - name='ip', - field=models.ForeignKey(default=1, to='networks.IPAddress', on_delete=django.db.models.deletion.CASCADE), + model_name="vip", + name="ip", + field=models.ForeignKey( + default=1, + to="networks.IPAddress", + on_delete=django.db.models.deletion.CASCADE, + ), preserve_default=False, ), migrations.AddField( - model_name='vip', - name='name', - field=models.CharField(default='', max_length=255, verbose_name='name'), + model_name="vip", + name="name", + field=models.CharField(default="", max_length=255, verbose_name="name"), preserve_default=False, ), migrations.AddField( - model_name='vip', - name='port', - field=models.PositiveIntegerField(default=0, verbose_name='port'), + model_name="vip", + name="port", + field=models.PositiveIntegerField(default=0, verbose_name="port"), ), migrations.AddField( - model_name='vip', - name='protocol', - field=models.PositiveIntegerField(default=1, choices=[(1, 'TCP'), (2, 'UDP')], verbose_name='protocol'), + model_name="vip", + name="protocol", + field=models.PositiveIntegerField( + default=1, choices=[(1, "TCP"), (2, "UDP")], verbose_name="protocol" + ), ), migrations.AlterUniqueTogether( - name='vip', - unique_together=set([('ip', 'port', 'protocol')]), + name="vip", + unique_together=set([("ip", "port", "protocol")]), ), ] diff --git a/src/ralph/data_center/migrations/0021_auto_20161003_0751.py b/src/ralph/data_center/migrations/0021_auto_20161003_0751.py index e23e58313b..c00c669a0d 100644 --- a/src/ralph/data_center/migrations/0021_auto_20161003_0751.py +++ b/src/ralph/data_center/migrations/0021_auto_20161003_0751.py @@ -6,20 +6,33 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0020_auto_20160907_1116'), + ("data_center", "0020_auto_20160907_1116"), ] operations = [ migrations.AlterField( - model_name='serverroom', - name='visualization_cols_num', - field=models.PositiveIntegerField(default=20, verbose_name='visualization grid columns number', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)]), + model_name="serverroom", + name="visualization_cols_num", + field=models.PositiveIntegerField( + default=20, + verbose_name="visualization grid columns number", + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100), + ], + ), ), migrations.AlterField( - model_name='serverroom', - name='visualization_rows_num', - field=models.PositiveIntegerField(default=20, verbose_name='visualization grid rows number', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)]), + model_name="serverroom", + name="visualization_rows_num", + field=models.PositiveIntegerField( + default=20, + verbose_name="visualization grid rows number", + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100), + ], + ), ), ] diff --git a/src/ralph/data_center/migrations/0022_auto_20161206_1521.py b/src/ralph/data_center/migrations/0022_auto_20161206_1521.py index 67ab9a42b1..5f33f8471d 100644 --- a/src/ralph/data_center/migrations/0022_auto_20161206_1521.py +++ b/src/ralph/data_center/migrations/0022_auto_20161206_1521.py @@ -1,20 +1,30 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0021_auto_20161003_0751'), + ("data_center", "0021_auto_20161003_0751"), ] operations = [ migrations.AlterField( - model_name='datacenterasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(choices=[(1, 'new'), (2, 'in use'), (3, 'free'), (4, 'damaged'), (5, 'liquidated'), (6, 'to deploy'), (7, 'cleaned')], default=1), + model_name="datacenterasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + choices=[ + (1, "new"), + (2, "in use"), + (3, "free"), + (4, "damaged"), + (5, "liquidated"), + (6, "to deploy"), + (7, "cleaned"), + ], + default=1, + ), ), ] diff --git a/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py b/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py index 31e41ed20b..a898a28f40 100644 --- a/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py +++ b/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py @@ -6,22 +6,22 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0022_auto_20161206_1521'), + ("data_center", "0022_auto_20161206_1521"), ] operations = [ migrations.AddField( - model_name='rack', - name='reverse_ordering', + model_name="rack", + name="reverse_ordering", field=models.BooleanField( - help_text=('Check if RU numbers count from top to bottom with ' - 'position 1 starting at the top of the rack. If ' - 'unchecked position 1 is at the bottom of the rack' + help_text=( + "Check if RU numbers count from top to bottom with " + "position 1 starting at the top of the rack. If " + "unchecked position 1 is at the bottom of the rack" ), default=settings.RACK_LISTING_NUMBERING_TOP_TO_BOTTOM, - verbose_name='RU order top to bottom', + verbose_name="RU order top to bottom", ), ), ] diff --git a/src/ralph/data_center/migrations/0024_auto_20170331_1341.py b/src/ralph/data_center/migrations/0024_auto_20170331_1341.py index 4cf18972c0..1d8358d753 100644 --- a/src/ralph/data_center/migrations/0024_auto_20170331_1341.py +++ b/src/ralph/data_center/migrations/0024_auto_20170331_1341.py @@ -6,15 +6,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0023_rack_reverse_ordering'), + ("data_center", "0023_rack_reverse_ordering"), ] operations = [ migrations.AlterField( - model_name='datacenterasset', - name='rack', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, blank=True, to='data_center.Rack'), + model_name="datacenterasset", + name="rack", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + blank=True, + to="data_center.Rack", + ), ), ] diff --git a/src/ralph/data_center/migrations/0025_auto_20170510_1122.py b/src/ralph/data_center/migrations/0025_auto_20170510_1122.py index 227c4e0998..2b8fa24240 100644 --- a/src/ralph/data_center/migrations/0025_auto_20170510_1122.py +++ b/src/ralph/data_center/migrations/0025_auto_20170510_1122.py @@ -1,20 +1,31 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0024_auto_20170331_1341'), + ("data_center", "0024_auto_20170331_1341"), ] operations = [ migrations.AlterField( - model_name='datacenterasset', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in use'), (3, 'free'), (4, 'damaged'), (5, 'liquidated'), (6, 'to deploy'), (7, 'cleaned'), (8, 'pre liquidated')]), + model_name="datacenterasset", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in use"), + (3, "free"), + (4, "damaged"), + (5, "liquidated"), + (6, "to deploy"), + (7, "cleaned"), + (8, "pre liquidated"), + ], + ), ), ] diff --git a/src/ralph/data_center/migrations/0026_auto_20170614_1237.py b/src/ralph/data_center/migrations/0026_auto_20170614_1237.py index b1ab607ea3..d024885361 100644 --- a/src/ralph/data_center/migrations/0026_auto_20170614_1237.py +++ b/src/ralph/data_center/migrations/0026_auto_20170614_1237.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0025_auto_20170510_1122'), + ("data_center", "0025_auto_20170510_1122"), ] operations = [ migrations.AlterField( - model_name='datacenterasset', - name='rack', - field=models.ForeignKey(null=True, to='data_center.Rack', on_delete=django.db.models.deletion.PROTECT), + model_name="datacenterasset", + name="rack", + field=models.ForeignKey( + null=True, + to="data_center.Rack", + on_delete=django.db.models.deletion.PROTECT, + ), ), ] diff --git a/src/ralph/data_center/migrations/0027_auto_20230831_1234.py b/src/ralph/data_center/migrations/0027_auto_20230831_1234.py index b933a97ba0..890a978340 100644 --- a/src/ralph/data_center/migrations/0027_auto_20230831_1234.py +++ b/src/ralph/data_center/migrations/0027_auto_20230831_1234.py @@ -5,50 +5,311 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0026_auto_20170614_1237'), + ("data_center", "0026_auto_20170614_1237"), ] operations = [ migrations.AddField( - model_name='datacenter', - name='address', - field=models.CharField(verbose_name='address', max_length=256, blank=True, null=True), + model_name="datacenter", + name="address", + field=models.CharField( + verbose_name="address", max_length=256, blank=True, null=True + ), ), migrations.AddField( - model_name='datacenter', - name='city', - field=models.CharField(verbose_name='city', max_length=256, blank=True, null=True), + model_name="datacenter", + name="city", + field=models.CharField( + verbose_name="city", max_length=256, blank=True, null=True + ), ), migrations.AddField( - model_name='datacenter', - name='company', - field=models.CharField(verbose_name='company', max_length=256, blank=True, null=True), + model_name="datacenter", + name="company", + field=models.CharField( + verbose_name="company", max_length=256, blank=True, null=True + ), ), migrations.AddField( - model_name='datacenter', - name='country', - field=models.PositiveIntegerField(verbose_name='country', blank=True, null=True, choices=[(1, 'Afghanistan'), (2, 'Albania'), (3, 'Algeria'), (4, 'American Samoa'), (5, 'Andorra'), (6, 'Angola'), (7, 'Anguilla'), (8, 'Antarctica'), (9, 'Antigua and Barbuda'), (10, 'Argentina'), (11, 'Armenia'), (12, 'Aruba'), (13, 'Australia'), (14, 'Austria'), (15, 'Azerbaijan'), (16, 'Bahamas'), (17, 'Bahrain'), (18, 'Bangladesh'), (19, 'Barbados'), (20, 'Belarus'), (21, 'Belgium'), (22, 'Belize'), (23, 'Benin'), (24, 'Bermuda'), (25, 'Bhutan'), (26, 'Bolivia'), (27, 'Bosnia and Herzegovina'), (28, 'Botswana'), (29, 'Brazil'), (30, 'Brunei'), (31, 'Bulgaria'), (32, 'Burkina Faso'), (33, 'Burundi'), (34, 'Cambodia'), (35, 'Cameroon'), (36, 'Canada'), (37, 'Cape Verde'), (38, 'Cayman Islands'), (39, 'Central African Republic'), (40, 'Chad'), (41, 'Chile'), (42, 'China'), (43, 'Colombia'), (44, 'Comoros'), (45, 'Congo Brazzaville'), (46, 'Congo Kinshasa'), (47, 'Cook Islands'), (48, 'Costa Rica'), (49, 'Cote Divoire'), (50, 'Croatia'), (51, 'Cuba'), (52, 'Cyprus'), (53, 'Czech Republic'), (54, 'Denmark'), (55, 'Djibouti'), (56, 'Dominica'), (57, 'Dominican Republic'), (58, 'Ecuador'), (59, 'Egypt'), (60, 'El Salvador'), (61, 'Equatorial Guinea'), (62, 'Eritrea'), (63, 'Estonia'), (64, 'Ethiopia'), (65, 'Faroe Islands'), (66, 'Fiji'), (67, 'Finland'), (68, 'France'), (69, 'French Polynesia'), (70, 'Gabon'), (71, 'Gambia'), (72, 'Georgia'), (73, 'Germany'), (74, 'Ghana'), (75, 'Gibraltar'), (76, 'Greece'), (77, 'Grenada'), (78, 'Guam'), (79, 'Guatemala'), (80, 'Guinea Bissau'), (81, 'Guinea'), (82, 'Guyana'), (83, 'Haiti'), (84, 'Honduras'), (85, 'Hong Kong'), (86, 'Hungary'), (87, 'Iceland'), (88, 'India'), (89, 'Indonesia'), (90, 'Iran'), (91, 'Iraq'), (92, 'Ireland'), (93, 'Israel'), (94, 'Italy'), (95, 'Jamaica'), (96, 'Japan'), (97, 'Jersey'), (98, 'Jordan'), (99, 'Kazakhstan'), (100, 'Kenya'), (101, 'Kiribati'), (102, 'Kuwait'), (103, 'Kyrgyzstan'), (104, 'Laos'), (105, 'Latvia'), (106, 'Lebanon'), (107, 'Lesotho'), (108, 'Liberia'), (109, 'Libya'), (110, 'Liechtenstein'), (111, 'Lithuania'), (112, 'Luxembourg'), (113, 'Macau'), (114, 'Macedonia'), (115, 'Madagascar'), (116, 'Malawi'), (117, 'Malaysia'), (118, 'Maldives'), (119, 'Mali'), (120, 'Malta'), (121, 'Marshall Islands'), (122, 'Mauritania'), (123, 'Mauritius'), (124, 'Mexico'), (125, 'Micronesia'), (126, 'Moldova'), (127, 'Monaco'), (128, 'Mongolia'), (129, 'Montenegro'), (130, 'Montserrat'), (131, 'Morocco'), (132, 'Mozambique'), (133, 'Myanmar'), (134, 'Namibia'), (135, 'Nauru'), (136, 'Nepal'), (137, 'Netherlands Antilles'), (138, 'Netherlands'), (139, 'New Zealand'), (140, 'Nicaragua'), (141, 'Niger'), (142, 'Nigeria'), (143, 'North Korea'), (144, 'Norway'), (145, 'Oman'), (146, 'Pakistan'), (147, 'Palau'), (148, 'Panama'), (149, 'Papua New Guinea'), (150, 'Paraguay'), (151, 'Peru'), (152, 'Philippines'), (153, 'Poland'), (154, 'Portugal'), (155, 'Puerto Rico'), (156, 'Qatar'), (157, 'Romania'), (158, 'Russian Federation'), (159, 'Rwanda'), (160, 'Saint Lucia'), (161, 'Samoa'), (162, 'San Marino'), (163, 'Sao Tome and Principe'), (164, 'Saudi Arabia'), (165, 'Senegal'), (166, 'Serbia'), (167, 'Seychelles'), (168, 'Sierra Leone'), (169, 'Singapore'), (170, 'Slovakia'), (171, 'Slovenia'), (172, 'Solomon Islands'), (173, 'Somalia'), (174, 'South Africa'), (175, 'South Korea'), (176, 'Spain'), (177, 'Sri Lanka'), (178, 'St Kitts and Nevis'), (179, 'St Vincent and the Grenadines'), (180, 'Sudan'), (181, 'Suriname'), (182, 'Swaziland'), (183, 'Sweden'), (184, 'Switzerland'), (185, 'Syria'), (186, 'Tajikistan'), (187, 'Taiwan'), (188, 'Tanzania'), (189, 'Thailand'), (190, 'Timor Leste'), (191, 'Togo'), (192, 'Tonga'), (193, 'Trinidad and Tobago'), (194, 'Tunisia'), (195, 'Turkey'), (196, 'Turkmenistan'), (197, 'Turks and Caicos Islands'), (198, 'Tuvalu'), (199, 'Uganda'), (200, 'Ukraine'), (201, 'United Arab Emirates'), (202, 'United Kingdom'), (203, 'United States of America'), (204, 'Uruguay'), (205, 'Uzbekistan'), (206, 'Vanuatu'), (207, 'Vatican City'), (208, 'Venezuela'), (209, 'Viet Nam'), (210, 'Virgin Islands British'), (211, 'Virgin Islands US'), (212, 'Western Sahara'), (213, 'Yemen'), (214, 'Zambia'), (215, 'Zimbabwe'), (301, 'England'), (302, 'Northern Ireland'), (303, 'Wales'), (304, 'Scotland'), (601, 'Northern Cyprus'), (602, 'Palestine'), (603, 'Somaliland'), (901, 'African Union'), (902, 'Arab League'), (903, 'Association of Southeast Asian Nations'), (904, 'Caricom'), (905, 'Commonwealth of Independent States'), (906, 'Commonwealth of Nations'), (907, 'European Union'), (908, 'Islamic Conference'), (909, 'NATO'), (910, 'Olimpic Movement'), (911, 'OPEC'), (912, 'Red Cross'), (913, 'United Nations')]), + model_name="datacenter", + name="country", + field=models.PositiveIntegerField( + verbose_name="country", + blank=True, + null=True, + choices=[ + (1, "Afghanistan"), + (2, "Albania"), + (3, "Algeria"), + (4, "American Samoa"), + (5, "Andorra"), + (6, "Angola"), + (7, "Anguilla"), + (8, "Antarctica"), + (9, "Antigua and Barbuda"), + (10, "Argentina"), + (11, "Armenia"), + (12, "Aruba"), + (13, "Australia"), + (14, "Austria"), + (15, "Azerbaijan"), + (16, "Bahamas"), + (17, "Bahrain"), + (18, "Bangladesh"), + (19, "Barbados"), + (20, "Belarus"), + (21, "Belgium"), + (22, "Belize"), + (23, "Benin"), + (24, "Bermuda"), + (25, "Bhutan"), + (26, "Bolivia"), + (27, "Bosnia and Herzegovina"), + (28, "Botswana"), + (29, "Brazil"), + (30, "Brunei"), + (31, "Bulgaria"), + (32, "Burkina Faso"), + (33, "Burundi"), + (34, "Cambodia"), + (35, "Cameroon"), + (36, "Canada"), + (37, "Cape Verde"), + (38, "Cayman Islands"), + (39, "Central African Republic"), + (40, "Chad"), + (41, "Chile"), + (42, "China"), + (43, "Colombia"), + (44, "Comoros"), + (45, "Congo Brazzaville"), + (46, "Congo Kinshasa"), + (47, "Cook Islands"), + (48, "Costa Rica"), + (49, "Cote Divoire"), + (50, "Croatia"), + (51, "Cuba"), + (52, "Cyprus"), + (53, "Czech Republic"), + (54, "Denmark"), + (55, "Djibouti"), + (56, "Dominica"), + (57, "Dominican Republic"), + (58, "Ecuador"), + (59, "Egypt"), + (60, "El Salvador"), + (61, "Equatorial Guinea"), + (62, "Eritrea"), + (63, "Estonia"), + (64, "Ethiopia"), + (65, "Faroe Islands"), + (66, "Fiji"), + (67, "Finland"), + (68, "France"), + (69, "French Polynesia"), + (70, "Gabon"), + (71, "Gambia"), + (72, "Georgia"), + (73, "Germany"), + (74, "Ghana"), + (75, "Gibraltar"), + (76, "Greece"), + (77, "Grenada"), + (78, "Guam"), + (79, "Guatemala"), + (80, "Guinea Bissau"), + (81, "Guinea"), + (82, "Guyana"), + (83, "Haiti"), + (84, "Honduras"), + (85, "Hong Kong"), + (86, "Hungary"), + (87, "Iceland"), + (88, "India"), + (89, "Indonesia"), + (90, "Iran"), + (91, "Iraq"), + (92, "Ireland"), + (93, "Israel"), + (94, "Italy"), + (95, "Jamaica"), + (96, "Japan"), + (97, "Jersey"), + (98, "Jordan"), + (99, "Kazakhstan"), + (100, "Kenya"), + (101, "Kiribati"), + (102, "Kuwait"), + (103, "Kyrgyzstan"), + (104, "Laos"), + (105, "Latvia"), + (106, "Lebanon"), + (107, "Lesotho"), + (108, "Liberia"), + (109, "Libya"), + (110, "Liechtenstein"), + (111, "Lithuania"), + (112, "Luxembourg"), + (113, "Macau"), + (114, "Macedonia"), + (115, "Madagascar"), + (116, "Malawi"), + (117, "Malaysia"), + (118, "Maldives"), + (119, "Mali"), + (120, "Malta"), + (121, "Marshall Islands"), + (122, "Mauritania"), + (123, "Mauritius"), + (124, "Mexico"), + (125, "Micronesia"), + (126, "Moldova"), + (127, "Monaco"), + (128, "Mongolia"), + (129, "Montenegro"), + (130, "Montserrat"), + (131, "Morocco"), + (132, "Mozambique"), + (133, "Myanmar"), + (134, "Namibia"), + (135, "Nauru"), + (136, "Nepal"), + (137, "Netherlands Antilles"), + (138, "Netherlands"), + (139, "New Zealand"), + (140, "Nicaragua"), + (141, "Niger"), + (142, "Nigeria"), + (143, "North Korea"), + (144, "Norway"), + (145, "Oman"), + (146, "Pakistan"), + (147, "Palau"), + (148, "Panama"), + (149, "Papua New Guinea"), + (150, "Paraguay"), + (151, "Peru"), + (152, "Philippines"), + (153, "Poland"), + (154, "Portugal"), + (155, "Puerto Rico"), + (156, "Qatar"), + (157, "Romania"), + (158, "Russian Federation"), + (159, "Rwanda"), + (160, "Saint Lucia"), + (161, "Samoa"), + (162, "San Marino"), + (163, "Sao Tome and Principe"), + (164, "Saudi Arabia"), + (165, "Senegal"), + (166, "Serbia"), + (167, "Seychelles"), + (168, "Sierra Leone"), + (169, "Singapore"), + (170, "Slovakia"), + (171, "Slovenia"), + (172, "Solomon Islands"), + (173, "Somalia"), + (174, "South Africa"), + (175, "South Korea"), + (176, "Spain"), + (177, "Sri Lanka"), + (178, "St Kitts and Nevis"), + (179, "St Vincent and the Grenadines"), + (180, "Sudan"), + (181, "Suriname"), + (182, "Swaziland"), + (183, "Sweden"), + (184, "Switzerland"), + (185, "Syria"), + (186, "Tajikistan"), + (187, "Taiwan"), + (188, "Tanzania"), + (189, "Thailand"), + (190, "Timor Leste"), + (191, "Togo"), + (192, "Tonga"), + (193, "Trinidad and Tobago"), + (194, "Tunisia"), + (195, "Turkey"), + (196, "Turkmenistan"), + (197, "Turks and Caicos Islands"), + (198, "Tuvalu"), + (199, "Uganda"), + (200, "Ukraine"), + (201, "United Arab Emirates"), + (202, "United Kingdom"), + (203, "United States of America"), + (204, "Uruguay"), + (205, "Uzbekistan"), + (206, "Vanuatu"), + (207, "Vatican City"), + (208, "Venezuela"), + (209, "Viet Nam"), + (210, "Virgin Islands British"), + (211, "Virgin Islands US"), + (212, "Western Sahara"), + (213, "Yemen"), + (214, "Zambia"), + (215, "Zimbabwe"), + (301, "England"), + (302, "Northern Ireland"), + (303, "Wales"), + (304, "Scotland"), + (601, "Northern Cyprus"), + (602, "Palestine"), + (603, "Somaliland"), + (901, "African Union"), + (902, "Arab League"), + (903, "Association of Southeast Asian Nations"), + (904, "Caricom"), + (905, "Commonwealth of Independent States"), + (906, "Commonwealth of Nations"), + (907, "European Union"), + (908, "Islamic Conference"), + (909, "NATO"), + (910, "Olimpic Movement"), + (911, "OPEC"), + (912, "Red Cross"), + (913, "United Nations"), + ], + ), ), migrations.AddField( - model_name='datacenter', - name='latitude', + model_name="datacenter", + name="latitude", field=models.FloatField(blank=True, null=True), ), migrations.AddField( - model_name='datacenter', - name='longitude', + model_name="datacenter", + name="longitude", field=models.FloatField(blank=True, null=True), ), migrations.AddField( - model_name='datacenter', - name='shortcut', - field=models.CharField(verbose_name='shortcut', max_length=256, blank=True, null=True), + model_name="datacenter", + name="shortcut", + field=models.CharField( + verbose_name="shortcut", max_length=256, blank=True, null=True + ), ), migrations.AddField( - model_name='datacenter', - name='type', - field=models.PositiveIntegerField(verbose_name='data center type', blank=True, null=True, choices=[(1, 'Data Center'), (2, 'Coworking space'), (3, 'Call center'), (4, 'Depot'), (5, 'Warehouse'), (6, 'Retail'), (7, 'Office')]), + model_name="datacenter", + name="type", + field=models.PositiveIntegerField( + verbose_name="data center type", + blank=True, + null=True, + choices=[ + (1, "Data Center"), + (2, "Coworking space"), + (3, "Call center"), + (4, "Depot"), + (5, "Warehouse"), + (6, "Retail"), + (7, "Office"), + ], + ), ), ] diff --git a/src/ralph/data_center/migrations/0028_auto_20230831_1354.py b/src/ralph/data_center/migrations/0028_auto_20230831_1354.py index 3b364de9ed..bb1e60b9a0 100644 --- a/src/ralph/data_center/migrations/0028_auto_20230831_1354.py +++ b/src/ralph/data_center/migrations/0028_auto_20230831_1354.py @@ -5,15 +5,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0027_auto_20230831_1234'), + ("data_center", "0027_auto_20230831_1234"), ] operations = [ migrations.AlterField( - model_name='datacenter', - name='type', - field=models.PositiveIntegerField(verbose_name='data center type', blank=True, null=True, choices=[(1, 'dc'), (2, 'cowork'), (3, 'call_center'), (4, 'depot'), (5, 'warehouse'), (6, 'retail'), (7, 'office')]), + model_name="datacenter", + name="type", + field=models.PositiveIntegerField( + verbose_name="data center type", + blank=True, + null=True, + choices=[ + (1, "dc"), + (2, "cowork"), + (3, "call_center"), + (4, "depot"), + (5, "warehouse"), + (6, "retail"), + (7, "office"), + ], + ), ), ] diff --git a/src/ralph/data_center/migrations/0029_auto_20230920_1102.py b/src/ralph/data_center/migrations/0029_auto_20230920_1102.py index 82f53de5d2..bc1702f1d8 100644 --- a/src/ralph/data_center/migrations/0029_auto_20230920_1102.py +++ b/src/ralph/data_center/migrations/0029_auto_20230920_1102.py @@ -5,15 +5,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0028_auto_20230831_1354'), + ("data_center", "0028_auto_20230831_1354"), ] operations = [ migrations.AlterField( - model_name='datacenter', - name='type', - field=models.PositiveIntegerField(verbose_name='data center type', blank=True, null=True, choices=[(1, 'dc'), (2, 'cowork'), (3, 'callcenter'), (4, 'depot'), (5, 'warehouse'), (6, 'retail'), (7, 'office')]), + model_name="datacenter", + name="type", + field=models.PositiveIntegerField( + verbose_name="data center type", + blank=True, + null=True, + choices=[ + (1, "dc"), + (2, "cowork"), + (3, "callcenter"), + (4, "depot"), + (5, "warehouse"), + (6, "retail"), + (7, "office"), + ], + ), ), ] diff --git a/src/ralph/data_center/migrations/0030_auto_20240221_1004.py b/src/ralph/data_center/migrations/0030_auto_20240221_1004.py index 6b88191d88..7ecb753efb 100644 --- a/src/ralph/data_center/migrations/0030_auto_20240221_1004.py +++ b/src/ralph/data_center/migrations/0030_auto_20240221_1004.py @@ -5,20 +5,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0029_auto_20230920_1102'), + ("data_center", "0029_auto_20230920_1102"), ] operations = [ migrations.AddField( - model_name='datacenterasset', - name='leasing_rate', - field=models.FloatField(verbose_name='Vendor contact number', blank=True, null=True), + model_name="datacenterasset", + name="leasing_rate", + field=models.FloatField( + verbose_name="Vendor contact number", blank=True, null=True + ), ), migrations.AddField( - model_name='datacenterasset', - name='vendor_contract_number', - field=models.CharField(verbose_name='Vendor contract number', max_length=256, blank=True, null=True), + model_name="datacenterasset", + name="vendor_contract_number", + field=models.CharField( + verbose_name="Vendor contract number", + max_length=256, + blank=True, + null=True, + ), ), ] diff --git a/src/ralph/data_center/migrations/0031_auto_20240304_1642.py b/src/ralph/data_center/migrations/0031_auto_20240304_1642.py index fbaf71125a..f4eaad4772 100644 --- a/src/ralph/data_center/migrations/0031_auto_20240304_1642.py +++ b/src/ralph/data_center/migrations/0031_auto_20240304_1642.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0030_auto_20240221_1004'), + ("data_center", "0030_auto_20240221_1004"), ] operations = [ migrations.AlterField( - model_name='datacenterasset', - name='leasing_rate', - field=models.FloatField(verbose_name='Leasing rate', blank=True, null=True), + model_name="datacenterasset", + name="leasing_rate", + field=models.FloatField(verbose_name="Leasing rate", blank=True, null=True), ), ] diff --git a/src/ralph/data_center/migrations/0032_auto_20240521_1542.py b/src/ralph/data_center/migrations/0032_auto_20240521_1542.py index 7b21b1880f..f7e1b406cf 100644 --- a/src/ralph/data_center/migrations/0032_auto_20240521_1542.py +++ b/src/ralph/data_center/migrations/0032_auto_20240521_1542.py @@ -7,15 +7,20 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0031_auto_20240304_1642'), + ("data_center", "0031_auto_20240304_1642"), ] operations = [ migrations.AlterField( - model_name='rack', - name='server_room', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='racks', to='data_center.ServerRoom', verbose_name='server room'), + model_name="rack", + name="server_room", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="racks", + to="data_center.ServerRoom", + verbose_name="server room", + ), ), ] diff --git a/src/ralph/data_center/migrations/0033_auto_20240621_1217.py b/src/ralph/data_center/migrations/0033_auto_20240621_1217.py index 13381cd4cc..b009a71ec9 100644 --- a/src/ralph/data_center/migrations/0033_auto_20240621_1217.py +++ b/src/ralph/data_center/migrations/0033_auto_20240621_1217.py @@ -7,39 +7,43 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0032_auto_20240521_1542'), + ("data_center", "0032_auto_20240521_1542"), ] operations = [ migrations.AlterModelManagers( - name='cluster', + name="cluster", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='database', + name="database", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='datacenterasset', + name="datacenterasset", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='vip', + name="vip", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterField( - model_name='baseobjectcluster', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, on_delete=django.db.models.deletion.CASCADE, related_name='clusters', to='assets.BaseObject'), + model_name="baseobjectcluster", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, + on_delete=django.db.models.deletion.CASCADE, + related_name="clusters", + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/data_center/migrations/0034_auto_20240628_1207.py b/src/ralph/data_center/migrations/0034_auto_20240628_1207.py index df8bf03a4e..6a2c9aa478 100644 --- a/src/ralph/data_center/migrations/0034_auto_20240628_1207.py +++ b/src/ralph/data_center/migrations/0034_auto_20240628_1207.py @@ -6,15 +6,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0033_auto_20240621_1217'), + ("data_center", "0033_auto_20240621_1217"), ] operations = [ migrations.AlterField( - model_name='baseobjectcluster', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_models=['data_center.Database', 'data_center.DataCenterAsset', 'virtual.CloudHost', 'virtual.VirtualServer'], on_delete=django.db.models.deletion.CASCADE, related_name='clusters', to='assets.BaseObject'), + model_name="baseobjectcluster", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_models=[ + "data_center.Database", + "data_center.DataCenterAsset", + "virtual.CloudHost", + "virtual.VirtualServer", + ], + on_delete=django.db.models.deletion.CASCADE, + related_name="clusters", + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/data_center/models/__init__.py b/src/ralph/data_center/models/__init__.py index cd86f9d8cb..a52f3e3a4f 100644 --- a/src/ralph/data_center/models/__init__.py +++ b/src/ralph/data_center/models/__init__.py @@ -30,26 +30,26 @@ ) __all__ = [ - 'Accessory', - 'BaseObjectCluster', - 'Connection', - 'ConnectionType', - 'Cluster', - 'ClusterStatus', - 'ClusterType', - 'Database', - 'DataCenter', - 'DataCenterAsset', - 'DataCenterAssetStatus', - 'DCHost', - 'DiskShare', - 'DiskShareMount', - 'Gap', - 'Orientation', - 'Rack', - 'RackAccessory', - 'RackOrientation', - 'ServerRoom', - 'VIP', - 'VIPProtocol', + "Accessory", + "BaseObjectCluster", + "Connection", + "ConnectionType", + "Cluster", + "ClusterStatus", + "ClusterType", + "Database", + "DataCenter", + "DataCenterAsset", + "DataCenterAssetStatus", + "DCHost", + "DiskShare", + "DiskShareMount", + "Gap", + "Orientation", + "Rack", + "RackAccessory", + "RackOrientation", + "ServerRoom", + "VIP", + "VIPProtocol", ] diff --git a/src/ralph/data_center/models/choices.py b/src/ralph/data_center/models/choices.py index 5a7c07d6c4..ffb48674af 100644 --- a/src/ralph/data_center/models/choices.py +++ b/src/ralph/data_center/models/choices.py @@ -6,13 +6,13 @@ class DataCenterAssetStatus(Choices): _ = Choices.Choice - new = _('new') - used = _('in use') - free = _('free') - damaged = _('damaged') - liquidated = _('liquidated') - to_deploy = _('to deploy') - cleaned = _('cleaned') + new = _("new") + used = _("in use") + free = _("free") + damaged = _("damaged") + liquidated = _("liquidated") + to_deploy = _("to deploy") + cleaned = _("cleaned") pre_liquidated = _("pre liquidated") @@ -30,16 +30,12 @@ class Orientation(Choices): @classmethod def is_width(cls, orientation): - is_width = orientation in set( - [choice.id for choice in cls.WIDTH.choices] - ) + is_width = orientation in set([choice.id for choice in cls.WIDTH.choices]) return is_width @classmethod def is_depth(cls, orientation): - is_depth = orientation in set( - [choice.id for choice in cls.DEPTH.choices] - ) + is_depth = orientation in set([choice.id for choice in cls.DEPTH.choices]) return is_depth diff --git a/src/ralph/data_center/models/components.py b/src/ralph/data_center/models/components.py index 3d948742b8..b8d1488f90 100644 --- a/src/ralph/data_center/models/components.py +++ b/src/ralph/data_center/models/components.py @@ -12,20 +12,31 @@ @python_2_unicode_compatible class DiskShare(Component): share_id = models.PositiveIntegerField( - verbose_name=_('share identifier'), null=True, blank=True, + verbose_name=_("share identifier"), + null=True, + blank=True, ) label = models.CharField( - verbose_name=_('name'), max_length=255, blank=True, null=True, + verbose_name=_("name"), + max_length=255, + blank=True, + null=True, default=None, ) size = models.PositiveIntegerField( - verbose_name=_('size (MiB)'), null=True, blank=True, + verbose_name=_("size (MiB)"), + null=True, + blank=True, ) snapshot_size = models.PositiveIntegerField( - verbose_name=_('size for snapshots (MiB)'), null=True, blank=True, + verbose_name=_("size for snapshots (MiB)"), + null=True, + blank=True, ) wwn = NullableCharField( - verbose_name=_('Volume serial'), max_length=33, unique=True, + verbose_name=_("Volume serial"), + max_length=33, + unique=True, ) full = models.BooleanField(default=True) @@ -33,42 +44,49 @@ def get_total_size(self): return (self.size or 0) + (self.snapshot_size or 0) class Meta: - verbose_name = _('disk share') - verbose_name_plural = _('disk shares') + verbose_name = _("disk share") + verbose_name_plural = _("disk shares") def __str__(self): - return '%s (%s)' % (self.label, self.wwn) + return "%s (%s)" % (self.label, self.wwn) @python_2_unicode_compatible class DiskShareMount(AdminAbsoluteUrlMixin, models.Model): - share = models.ForeignKey(DiskShare, verbose_name=_("share"), on_delete=models.CASCADE) + share = models.ForeignKey( + DiskShare, verbose_name=_("share"), on_delete=models.CASCADE + ) asset = models.ForeignKey( - Asset, verbose_name=_('asset'), null=True, blank=True, - default=None, on_delete=models.SET_NULL + Asset, + verbose_name=_("asset"), + null=True, + blank=True, + default=None, + on_delete=models.SET_NULL, ) volume = models.CharField( - verbose_name=_('volume'), max_length=255, blank=True, - null=True, default=None + verbose_name=_("volume"), max_length=255, blank=True, null=True, default=None ) size = models.PositiveIntegerField( - verbose_name=_('size (MiB)'), null=True, blank=True, + verbose_name=_("size (MiB)"), + null=True, + blank=True, ) def get_total_mounts(self): - return self.share.disksharemount_set.exclude( - device=None - ).filter( - is_virtual=False - ).count() + return ( + self.share.disksharemount_set.exclude(device=None) + .filter(is_virtual=False) + .count() + ) def get_size(self): return self.size or self.share.get_total_size() class Meta: - unique_together = ('share', 'asset') - verbose_name = _('disk share mount') - verbose_name_plural = _('disk share mounts') + unique_together = ("share", "asset") + verbose_name = _("disk share mount") + verbose_name_plural = _("disk share mounts") def __str__(self): - return '%s@%r' % (self.volume, self.asset) + return "%s@%r" % (self.volume, self.asset) diff --git a/src/ralph/data_center/models/mixins.py b/src/ralph/data_center/models/mixins.py index 57d83d2f3c..bdd2fda1e3 100644 --- a/src/ralph/data_center/models/mixins.py +++ b/src/ralph/data_center/models/mixins.py @@ -19,10 +19,13 @@ class WithManagementIPMixin(object): * if no, it's attached to current object and marked as management ip """ + def _get_management_ip(self): - eth = self.ethernet_set.select_related('ipaddress').filter( - ipaddress__is_management=True - ).first() + eth = ( + self.ethernet_set.select_related("ipaddress") + .filter(ipaddress__is_management=True) + .first() + ) if eth: return eth.ipaddress return None @@ -44,12 +47,9 @@ def _create_new_ip(): ip = _create_new_ip() else: # check if it's not assigned to any object - if ( - ip.ethernet and - ip.ethernet.base_object_id != self.pk - ): + if ip.ethernet and ip.ethernet.base_object_id != self.pk: raise ValidationError( - 'IP is already assigned to {}'.format( + "IP is already assigned to {}".format( ip.ethernet.base_object.last_descendant ) ) @@ -70,7 +70,7 @@ def management_ip(self): ip = self._get_management_ip() if ip: return ip.address - return '' + return "" @management_ip.setter def management_ip(self, value): @@ -100,8 +100,8 @@ def management_ip(self): def management_hostname(self): ip = self._get_management_ip() if ip: - return ip.hostname or '' - return '' + return ip.hostname or "" + return "" @management_hostname.setter def management_hostname(self, value): diff --git a/src/ralph/data_center/models/physical.py b/src/ralph/data_center/models/physical.py index 358a53c2f6..dcbec967e6 100644 --- a/src/ralph/data_center/models/physical.py +++ b/src/ralph/data_center/models/physical.py @@ -8,11 +8,7 @@ from django import forms from django.conf import settings from django.core.exceptions import ValidationError -from django.core.validators import ( - MaxValueValidator, - MinValueValidator, - RegexValidator -) +from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator from django.db import models, transaction from django.db.models import Q from django.urls import reverse @@ -35,7 +31,7 @@ ConnectionType, DataCenterAssetStatus, Orientation, - RackOrientation + RackOrientation, ) from ralph.data_center.models.mixins import WithManagementIPMixin from ralph.data_center.publishers import publish_host_update @@ -49,10 +45,14 @@ logger = logging.getLogger(__name__) # i.e. number in range 1-16 and optional postfix 'A' or 'B' -VALID_SLOT_NUMBER_FORMAT = re.compile('^([1-9][A,B]?|1[0-6][A,B]?)$') +VALID_SLOT_NUMBER_FORMAT = re.compile("^([1-9][A,B]?|1[0-6][A,B]?)$") ACCESSORY_DATA = [ - 'brush', 'patch_panel_fc', 'patch_panel_utp', 'organizer', 'power_socket' + "brush", + "patch_panel_fc", + "patch_panel_utp", + "organizer", + "power_socket", ] @@ -69,9 +69,7 @@ def assign_additional_hostname_choices(actions, objects): """ networks = [] for obj in objects: - networks.append( - set(obj._get_available_networks()) - ) + networks.append(set(obj._get_available_networks())) networks = set.intersection(*networks) choices = [(str(net.pk), net) for net in networks] return choices @@ -81,10 +79,10 @@ class Gap(object): """A placeholder that represents a gap in a blade chassis""" id = 0 - barcode = '-' - sn = '-' - service = namedtuple('Service', ['name'])('-') - model = namedtuple('Model', ['name'])('-') + barcode = "-" + sn = "-" + service = namedtuple("Service", ["name"])("-") + model = namedtuple("Model", ["name"])("-") linked_device = None def __init__(self, slot_no, orientation): @@ -95,22 +93,20 @@ def get_orientation_desc(self): return self.orientation def get_absolute_url(self): - return '' + return "" @classmethod def generate_gaps(cls, items): def get_number(slot_no): """Returns the integer part of slot number""" - m = re.match(r'(\d+)', slot_no) + m = re.match(r"(\d+)", slot_no) return (m and int(m.group(0))) or 0 + if not items: return [] - max_slot_no = max([ - get_number(asset.slot_no) - for asset in items - ]) + max_slot_no = max([get_number(asset.slot_no) for asset in items]) first_asset_slot_no = items[0].slot_no - ab = first_asset_slot_no and first_asset_slot_no[-1] in {'A', 'B'} + ab = first_asset_slot_no and first_asset_slot_no[-1] in {"A", "B"} slot_nos = {asset.slot_no for asset in items} def handle_missing(slot_no): @@ -119,7 +115,7 @@ def handle_missing(slot_no): for slot_no in range(1, max_slot_no + 1): if ab: - for letter in ['A', 'B']: + for letter in ["A", "B"]: handle_missing(str(slot_no) + letter) else: handle_missing(str(slot_no)) @@ -144,22 +140,24 @@ class DataCenter(AdminAbsoluteUrlMixin, NamedMixin, models.Model): show_on_dashboard = models.BooleanField(default=True) company = models.CharField( - verbose_name=_('company'), max_length=256, blank=True, null=True) + verbose_name=_("company"), max_length=256, blank=True, null=True + ) country = models.PositiveIntegerField( - verbose_name=_('country'), - choices=Country(), - blank=True, - null=True + verbose_name=_("country"), choices=Country(), blank=True, null=True ) city = models.CharField( - verbose_name=_('city'), max_length=256, blank=True, null=True) + verbose_name=_("city"), max_length=256, blank=True, null=True + ) address = models.CharField( - verbose_name=_('address'), max_length=256, blank=True, null=True) + verbose_name=_("address"), max_length=256, blank=True, null=True + ) latitude = models.FloatField(null=True, blank=True) longitude = models.FloatField(null=True, blank=True) type = models.PositiveIntegerField( - verbose_name=_("data center type"), choices=DataCenterType(), - blank=True, null=True + verbose_name=_("data center type"), + choices=DataCenterType(), + blank=True, + null=True, ) shortcut = models.CharField( verbose_name=_("shortcut"), max_length=256, blank=True, null=True @@ -167,9 +165,9 @@ class DataCenter(AdminAbsoluteUrlMixin, NamedMixin, models.Model): @property def rack_set(self): - return Rack.objects.select_related( - 'server_room' - ).filter(server_room__data_center=self) + return Rack.objects.select_related("server_room").filter( + server_room__data_center=self + ) @property def server_rooms(self): @@ -184,8 +182,8 @@ def get_queryset(self): return ( super() .get_queryset() - .select_related('data_center') - .prefetch_related('racks') + .select_related("data_center") + .prefetch_related("racks") ) @@ -193,66 +191,64 @@ class ServerRoom(AdminAbsoluteUrlMixin, NamedMixin.NonUnique, models.Model): _allow_in_dashboard = True data_center = models.ForeignKey( - DataCenter, - verbose_name=_("data center"), - on_delete=models.CASCADE + DataCenter, verbose_name=_("data center"), on_delete=models.CASCADE ) data_center._autocomplete = False - data_center._filter_title = _('data center') + data_center._filter_title = _("data center") visualization_cols_num = models.PositiveIntegerField( - verbose_name=_('visualization grid columns number'), + verbose_name=_("visualization grid columns number"), default=20, validators=[ MinValueValidator(1), - MaxValueValidator(100) # is correlate with $grid-count - ] + MaxValueValidator(100), # is correlate with $grid-count + ], ) visualization_rows_num = models.PositiveIntegerField( - verbose_name=_('visualization grid rows number'), + verbose_name=_("visualization grid rows number"), default=20, validators=[ MinValueValidator(1), - MaxValueValidator(100) # is correlate with $grid-count - ] + MaxValueValidator(100), # is correlate with $grid-count + ], ) objects = ServerRoomManager() def __str__(self): - return '{} ({})'.format(self.name, self.data_center.name) + return "{} ({})".format(self.name, self.data_center.name) class Accessory(AdminAbsoluteUrlMixin, NamedMixin): - class Meta: - verbose_name = _('accessory') - verbose_name_plural = _('accessories') + verbose_name = _("accessory") + verbose_name_plural = _("accessories") class RackAccessory(AdminAbsoluteUrlMixin, models.Model): accessory = models.ForeignKey(Accessory, on_delete=models.CASCADE) - rack = models.ForeignKey('Rack', on_delete=models.CASCADE) + rack = models.ForeignKey("Rack", on_delete=models.CASCADE) orientation = models.PositiveIntegerField( choices=Orientation(), default=Orientation.front.id, ) position = models.IntegerField(null=True, blank=False) remarks = models.CharField( - verbose_name='Additional remarks', + verbose_name="Additional remarks", max_length=1024, blank=True, ) class Meta: - verbose_name_plural = _('rack accessories') + verbose_name_plural = _("rack accessories") def get_orientation_desc(self): return Orientation.name_from_id(self.orientation) def __str__(self): - rack_name = self.rack.name if self.rack else '' - accessory_name = self.accessory.name if self.accessory else '' - return '{rack_name} - {accessory_name}'.format( - rack_name=rack_name, accessory_name=accessory_name, + rack_name = self.rack.name if self.rack else "" + accessory_name = self.accessory.name if self.accessory else "" + return "{rack_name} - {accessory_name}".format( + rack_name=rack_name, + accessory_name=accessory_name, ) @@ -260,7 +256,7 @@ class RackManager(models.Manager): pass def get_queryset(self): - return super().get_queryset().select_related('server_room__data_center') + return super().get_queryset().select_related("server_room__data_center") class Rack(AdminAbsoluteUrlMixin, NamedMixin.NonUnique, models.Model): @@ -269,17 +265,16 @@ class Rack(AdminAbsoluteUrlMixin, NamedMixin.NonUnique, models.Model): objects = RackManager() server_room = models.ForeignKey( - ServerRoom, verbose_name=_('server room'), + ServerRoom, + verbose_name=_("server room"), null=True, blank=False, - related_name='racks', - on_delete=models.CASCADE + related_name="racks", + on_delete=models.CASCADE, ) server_room._autocomplete = False - server_room._filter_title = _('server room') - description = models.CharField( - _('description'), max_length=250, blank=True - ) + server_room._filter_title = _("server room") + description = models.CharField(_("description"), max_length=250, blank=True) orientation = models.PositiveIntegerField( choices=RackOrientation(), default=RackOrientation.top.id, @@ -287,33 +282,33 @@ class Rack(AdminAbsoluteUrlMixin, NamedMixin.NonUnique, models.Model): max_u_height = models.IntegerField(default=48) visualization_col = models.PositiveIntegerField( - verbose_name=_('column number on visualization grid'), + verbose_name=_("column number on visualization grid"), default=0, ) visualization_row = models.PositiveIntegerField( - verbose_name=_('row number on visualization grid'), + verbose_name=_("row number on visualization grid"), default=0, ) - accessories = models.ManyToManyField(Accessory, through='RackAccessory') + accessories = models.ManyToManyField(Accessory, through="RackAccessory") require_position = models.BooleanField( default=True, help_text=_( - 'Uncheck if position is optional for this rack (ex. when rack ' - 'has warehouse-kind role' - ) + "Uncheck if position is optional for this rack (ex. when rack " + "has warehouse-kind role" + ), ) reverse_ordering = models.BooleanField( default=settings.RACK_LISTING_NUMBERING_TOP_TO_BOTTOM, help_text=_( - 'Check if RU numbers count from top to bottom with position 1 ' - 'starting at the top of the rack. If unchecked position 1 is ' - 'at the bottom of the rack' + "Check if RU numbers count from top to bottom with position 1 " + "starting at the top of the rack. If unchecked position 1 is " + "at the bottom of the rack" ), - verbose_name=_('RU order top to bottom'), + verbose_name=_("RU order top to bottom"), ) class Meta: - unique_together = ('name', 'server_room') + unique_together = ("name", "server_room") def __str__(self): if self.server_room: @@ -329,26 +324,23 @@ def get_orientation_desc(self): def get_root_assets(self, side=None): filter_kwargs = { - 'rack': self, + "rack": self, } if side: - filter_kwargs['orientation'] = side + filter_kwargs["orientation"] = side else: - filter_kwargs['orientation__in'] = [ - Orientation.front, Orientation.back - ] - return DataCenterAsset.objects.select_related( - 'model__category' - ).filter( - Q(slot_no='') | Q(slot_no=None), **filter_kwargs - ).exclude(model__has_parent=True) + filter_kwargs["orientation__in"] = [Orientation.front, Orientation.back] + return ( + DataCenterAsset.objects.select_related("model__category") + .filter(Q(slot_no="") | Q(slot_no=None), **filter_kwargs) + .exclude(model__has_parent=True) + ) def get_free_u(self): u_list = [True] * self.max_u_height - accessories = RackAccessory.objects.values_list( - 'position').filter(rack=self) + accessories = RackAccessory.objects.values_list("position").filter(rack=self) dc_assets = self.get_root_assets().values_list( - 'position', 'model__height_of_device' + "position", "model__height_of_device" ) def fill_u_list(objects, height_of_device=lambda obj: 1): @@ -361,18 +353,17 @@ def fill_u_list(objects, height_of_device=lambda obj: 1): continue start = obj[0] - 1 - end = min( - self.max_u_height, obj[0] + int(height_of_device(obj)) - 1 - ) + end = min(self.max_u_height, obj[0] + int(height_of_device(obj)) - 1) height = end - start if height: u_list[start:end] = [False] * height + fill_u_list(accessories) fill_u_list(dc_assets, lambda obj: obj[1]) return sum(u_list) def get_pdus(self): - return DataCenterAsset.objects.select_related('model').filter( + return DataCenterAsset.objects.select_related("model").filter( rack=self, orientation__in=(Orientation.left, Orientation.right), position=0, @@ -381,11 +372,13 @@ def get_pdus(self): class NetworkableBaseObject(models.Model): # TODO: hostname field and not-abstract cls - custom_fields_inheritance = OrderedDict([ - ('configuration_path', 'assets.ConfigurationClass'), - ('configuration_path__module', 'assets.ConfigurationModule'), - ('service_env', 'assets.ServiceEnvironment'), - ]) + custom_fields_inheritance = OrderedDict( + [ + ("configuration_path", "assets.ConfigurationClass"), + ("configuration_path__module", "assets.ConfigurationModule"), + ("service_env", "assets.ServiceEnvironment"), + ] + ) @cached_property def network_environment(self): @@ -403,13 +396,17 @@ def network_environment(self): """ if self.rack_id: # TODO: better handling (when server in multiple environments) - return NetworkEnvironment.objects.filter( - network__racks=self.rack, - # filter env by ips assigned to current object - network__in=self.ipaddresses.filter( - is_management=False - ).values_list('network', flat=True) - ).distinct().first() + return ( + NetworkEnvironment.objects.filter( + network__racks=self.rack, + # filter env by ips assigned to current object + network__in=self.ipaddresses.filter( + is_management=False + ).values_list("network", flat=True), + ) + .distinct() + .first() + ) @property def ipaddresses(self): @@ -422,8 +419,8 @@ def get_next_free_hostname(self): """ if self.network_environment: return self.network_environment.next_free_hostname - logger.warning('Network-environment not provided for %s', self) - return '' + logger.warning("Network-environment not provided for %s", self) + return "" def issue_next_free_hostname(self): """ @@ -432,19 +429,19 @@ def issue_next_free_hostname(self): """ if self.network_environment: return self.network_environment.issue_next_free_hostname() - logger.warning('Network-environment not provided for %s', self) - return '' + logger.warning("Network-environment not provided for %s", self) + return "" def _get_available_network_environments(self): if self.rack_id: - return list(NetworkEnvironment.objects.filter( - network__racks=self.rack_id - ).distinct()) + return list( + NetworkEnvironment.objects.filter( + network__racks=self.rack_id + ).distinct() + ) return NetworkEnvironment.objects.none() - def _get_available_networks( - self, as_query=False, is_broadcasted_in_dhcp=False - ): + def _get_available_networks(self, as_query=False, is_broadcasted_in_dhcp=False): if self.rack_id: query = Network.objects.filter(racks=self.rack_id).distinct() else: @@ -464,15 +461,13 @@ class DataCenterAsset( WithManagementIPMixin, NetworkableBaseObject, AutocompleteTooltipMixin, - Asset + Asset, ): _allow_in_dashboard = True - previous_dc_host_update_fields = ['hostname'] + previous_dc_host_update_fields = ["hostname"] - rack = models.ForeignKey( - Rack, null=True, blank=False, on_delete=models.PROTECT - ) + rack = models.ForeignKey(Rack, null=True, blank=False, on_delete=models.PROTECT) status = TransitionField( default=DataCenterAssetStatus.new.id, choices=DataCenterAssetStatus(), @@ -486,16 +481,16 @@ class DataCenterAsset( null=True, blank=True, max_length=256, - verbose_name=_('Vendor contract number'), + verbose_name=_("Vendor contract number"), ) leasing_rate = models.FloatField( null=True, blank=True, - verbose_name=_('Leasing rate'), + verbose_name=_("Leasing rate"), ) slot_no = models.CharField( blank=True, - help_text=_('Fill it if asset is blade server'), + help_text=_("Fill it if asset is blade server"), max_length=3, null=True, validators=[ @@ -505,26 +500,26 @@ class DataCenterAsset( "Slot number should be a number from range 1-16 with " "an optional postfix 'A' or 'B' (e.g. '16A')" ), - code='invalid_slot_no' + code="invalid_slot_no", ) ], - verbose_name=_('slot number'), + verbose_name=_("slot number"), ) firmware_version = models.CharField( null=True, blank=True, max_length=256, - verbose_name=_('firmware version'), + verbose_name=_("firmware version"), ) bios_version = models.CharField( null=True, blank=True, max_length=256, - verbose_name=_('BIOS version'), + verbose_name=_("BIOS version"), ) connections = models.ManyToManyField( - 'self', - through='Connection', + "self", + through="Connection", symmetrical=False, ) source = models.PositiveIntegerField( @@ -539,43 +534,41 @@ class DataCenterAsset( production_use_date = models.DateField(null=True, blank=True) autocomplete_tooltip_fields = [ - 'rack', - 'barcode', - 'sn', + "rack", + "barcode", + "sn", ] _summary_fields = [ - ('hostname', 'Hostname'), - ('location', 'Location'), - ('model__name', 'Model'), + ("hostname", "Hostname"), + ("location", "Location"), + ("model__name", "Model"), ] class Meta: - verbose_name = _('data center asset') - verbose_name_plural = _('data center assets') + verbose_name = _("data center asset") + verbose_name_plural = _("data center assets") abstract = False def __str__(self): - return '{} (BC: {} / SN: {})'.format( - self.hostname or '-', self.barcode or '-', self.sn or '-' + return "{} (BC: {} / SN: {})".format( + self.hostname or "-", self.barcode or "-", self.sn or "-" ) def __repr__(self): - return ''.format(self.id) + return "".format(self.id) def save(self, *args, **kwargs): super().save(*args, **kwargs) if self.pk: # When changing rack we search and save all descendants - if self._previous_state['rack_id'] != self.rack_id: - DataCenterAsset.objects.filter( - parent=self - ).update(rack=self.rack) + if self._previous_state["rack_id"] != self.rack_id: + DataCenterAsset.objects.filter(parent=self).update(rack=self.rack) # When changing position if is blade, # we search and save all descendants - if self._previous_state['position'] != self.position: - DataCenterAsset.objects.filter( - parent=self - ).update(position=self.position) + if self._previous_state["position"] != self.position: + DataCenterAsset.objects.filter(parent=self).update( + position=self.position + ) def get_orientation_desc(self): return Orientation.name_from_id(self.orientation) @@ -583,11 +576,13 @@ def get_orientation_desc(self): def get_location(self): location = [] if self.rack: - location.extend([ - self.rack.server_room.data_center.name, - self.rack.server_room.name, - self.rack.name - ]) + location.extend( + [ + self.rack.server_room.data_center.name, + self.rack.server_room.name, + self.rack.name, + ] + ) if self.position: location.append(str(self.position)) if self.slot_no: @@ -612,46 +607,49 @@ def location(self): Additional column 'location' display filter by: data center, server_room, rack, position (if is blade) """ - base_url = reverse('admin:data_center_datacenterasset_changelist') + base_url = reverse("admin:data_center_datacenterasset_changelist") position = self.position if self.is_blade: position = generate_html_link( base_url, label=position, params={ - 'rack': self.rack_id, - 'position__start': self.position, - 'position__end': self.position + "rack": self.rack_id, + "position__start": self.position, + "position__end": self.position, }, ) - result = [ - generate_html_link( - base_url, - label=self.rack.server_room.data_center.name, - params={ - 'rack__server_room__data_center': - self.rack.server_room.data_center_id - }, - ), - generate_html_link( - base_url, - label=self.rack.server_room.name, - params={'rack__server_room': self.rack.server_room_id}, - ), - generate_html_link( - base_url, - label=self.rack.name, - params={'rack': self.rack_id}, - ) - ] if self.rack and self.rack.server_room else [] + result = ( + [ + generate_html_link( + base_url, + label=self.rack.server_room.data_center.name, + params={ + "rack__server_room__data_center": self.rack.server_room.data_center_id + }, + ), + generate_html_link( + base_url, + label=self.rack.server_room.name, + params={"rack__server_room": self.rack.server_room_id}, + ), + generate_html_link( + base_url, + label=self.rack.name, + params={"rack": self.rack_id}, + ), + ] + if self.rack and self.rack.server_room + else [] + ) if self.position: result.append(str(position)) if self.slot_no: result.append(str(self.slot_no)) - return ' / '.join(result) if self.rack else '—' + return " / ".join(result) if self.rack else "—" def _validate_orientation(self): """ @@ -660,82 +658,79 @@ def _validate_orientation(self): if self.position is None: return if self.position == 0 and not Orientation.is_width(self.orientation): - msg = 'Valid orientations for picked position are: {}'.format( - ', '.join( - choice.desc for choice in Orientation.WIDTH.choices - ) + msg = "Valid orientations for picked position are: {}".format( + ", ".join(choice.desc for choice in Orientation.WIDTH.choices) ) - raise ValidationError({'orientation': [msg]}) + raise ValidationError({"orientation": [msg]}) if self.position > 0 and not Orientation.is_depth(self.orientation): - msg = 'Valid orientations for picked position are: {}'.format( - ', '.join( - choice.desc for choice in Orientation.DEPTH.choices - ) + msg = "Valid orientations for picked position are: {}".format( + ", ".join(choice.desc for choice in Orientation.DEPTH.choices) ) - raise ValidationError({'orientation': [msg]}) + raise ValidationError({"orientation": [msg]}) def _validate_position(self): """ Validate if position not empty when rack requires it. """ - if ( - self.rack and - self.position is None and - self.rack.require_position - ): - msg = 'Position is required for this rack' - raise ValidationError({'position': [msg]}) + if self.rack and self.position is None and self.rack.require_position: + msg = "Position is required for this rack" + raise ValidationError({"position": [msg]}) def _validate_position_in_rack(self): """ Validate if position is in rack height range. """ if ( - self.rack and - self.position is not None and - self.position > self.rack.max_u_height + self.rack + and self.position is not None + and self.position > self.rack.max_u_height ): msg = 'Position is higher than "max u height" = {}'.format( self.rack.max_u_height, ) - raise ValidationError({'position': [msg]}) + raise ValidationError({"position": [msg]}) if self.position is not None and self.position < 0: - msg = 'Position should be 0 or greater' - raise ValidationError({'position': msg}) + msg = "Position should be 0 or greater" + raise ValidationError({"position": msg}) def _validate_slot_no(self): if self.model_id: if self.model.has_parent and not self.slot_no: - raise ValidationError({ - 'slot_no': 'Slot number is required when asset is blade' - }) + raise ValidationError( + {"slot_no": "Slot number is required when asset is blade"} + ) if not self.model.has_parent and self.slot_no: - raise ValidationError({ - 'slot_no': ( - 'Slot number cannot be filled when asset is not blade' - ) - }) + raise ValidationError( + { + "slot_no": ( + "Slot number cannot be filled when asset is not blade" + ) + } + ) if self.parent: - dc_asset_with_slot_no = DataCenterAsset.objects.filter( - parent=self.parent, slot_no=self.slot_no, - orientation=self.orientation, - ).exclude(pk=self.pk).first() + dc_asset_with_slot_no = ( + DataCenterAsset.objects.filter( + parent=self.parent, + slot_no=self.slot_no, + orientation=self.orientation, + ) + .exclude(pk=self.pk) + .first() + ) if dc_asset_with_slot_no: message = mark_safe( ( - 'Slot is already occupied by: ' + "Slot is already occupied by: " '{}' ).format( reverse( - 'admin:data_center_datacenterasset_change', - args=[dc_asset_with_slot_no.id] + "admin:data_center_datacenterasset_change", + args=[dc_asset_with_slot_no.id], ), - dc_asset_with_slot_no + dc_asset_with_slot_no, ) ) - raise ValidationError({ - 'slot_no': message - }) + raise ValidationError({"slot_no": message}) def clean(self): # TODO: this should be default logic of clean method; @@ -761,77 +756,77 @@ def get_related_assets(self): orientations = [Orientation.front, Orientation.back] assets_by_orientation = [] for orientation in orientations: - assets_by_orientation.append(list( - DataCenterAsset.objects.select_related('model').filter( - parent=self, - orientation=orientation, - model__has_parent=True, - ).exclude(id=self.id) - )) - assets = [ - Gap.generate_gaps(assets) for assets in assets_by_orientation - ] + assets_by_orientation.append( + list( + DataCenterAsset.objects.select_related("model") + .filter( + parent=self, + orientation=orientation, + model__has_parent=True, + ) + .exclude(id=self.id) + ) + ) + assets = [Gap.generate_gaps(assets) for assets in assets_by_orientation] return chain(*assets) @classmethod def get_autocomplete_queryset(cls): - return cls._default_manager.exclude( - status=DataCenterAssetStatus.liquidated.id - ) + return cls._default_manager.exclude(status=DataCenterAssetStatus.liquidated.id) @classmethod @transition_action( - verbose_name=_('Change rack'), + verbose_name=_("Change rack"), form_fields={ - 'rack': { - 'field': forms.CharField(widget=AutocompleteWidget( - field=rack, admin_site=ralph_site - )), + "rack": { + "field": forms.CharField( + widget=AutocompleteWidget(field=rack, admin_site=ralph_site) + ), } - } + }, ) def change_rack(cls, instances, **kwargs): - rack = Rack.objects.get(pk=kwargs['rack']) + rack = Rack.objects.get(pk=kwargs["rack"]) for instance in instances: instance.rack = rack @classmethod @transition_action( - verbose_name=_('Convert to BackOffice Asset'), + verbose_name=_("Convert to BackOffice Asset"), disable_save_object=True, only_one_action=True, form_fields={ - 'warehouse': { - 'field': forms.CharField(label=_('Warehouse')), - 'autocomplete_field': 'warehouse', - 'autocomplete_model': 'back_office.BackOfficeAsset' + "warehouse": { + "field": forms.CharField(label=_("Warehouse")), + "autocomplete_field": "warehouse", + "autocomplete_model": "back_office.BackOfficeAsset", }, - 'region': { - 'field': forms.CharField(label=_('Region')), - 'autocomplete_field': 'region', - 'autocomplete_model': 'back_office.BackOfficeAsset' - } - } + "region": { + "field": forms.CharField(label=_("Region")), + "autocomplete_field": "region", + "autocomplete_model": "back_office.BackOfficeAsset", + }, + }, ) def convert_to_backoffice_asset(cls, instances, **kwargs): with transaction.atomic(): for i, instance in enumerate(instances): back_office_asset = BackOfficeAsset() - back_office_asset.region = Region.objects.get( - pk=kwargs['region'] - ) + back_office_asset.region = Region.objects.get(pk=kwargs["region"]) back_office_asset.warehouse = Warehouse.objects.get( - pk=kwargs['warehouse'] + pk=kwargs["warehouse"] ) target_status = int( - Transition.objects.values_list('target', flat=True).get(pk=kwargs['transition_id']) # noqa + Transition.objects.values_list("target", flat=True).get( + pk=kwargs["transition_id"] + ) # noqa ) back_office_asset.status = dc_asset_to_bo_asset_status_converter( # noqa instance.status, target_status ) move_parents_models( - instance, back_office_asset, exclude_copy_fields=['status'] + instance, back_office_asset, exclude_copy_fields=["status"] ) # Save new asset to list, required to redirect url. # RunTransitionView.get_success_url() @@ -839,27 +834,24 @@ def convert_to_backoffice_asset(cls, instances, **kwargs): @classmethod @transition_action( - verbose_name=_('Cleanup scm status'), + verbose_name=_("Cleanup scm status"), ) def cleanup_scm_statuscheck(cls, instances, **kwargs): with transaction.atomic(): for instance in instances: try: instance.scmstatuscheck.delete() - except DataCenterAsset.scmstatuscheck.\ - RelatedObjectDoesNotExist: + except DataCenterAsset.scmstatuscheck.RelatedObjectDoesNotExist: pass @classmethod @transition_action( - verbose_name=_('Assign additional IP and hostname pair'), + verbose_name=_("Assign additional IP and hostname pair"), form_fields={ - 'network_pk': { - 'field': forms.ChoiceField( - label=_('Select network') - ), - 'choices': assign_additional_hostname_choices, - 'exclude_from_history': True, + "network_pk": { + "field": forms.ChoiceField(label=_("Select network")), + "choices": assign_additional_hostname_choices, + "exclude_from_history": True, }, }, ) @@ -880,29 +872,24 @@ def assign_additional_hostname(cls, instances, network_pk, **kwargs): class Connection(AdminAbsoluteUrlMixin, models.Model): outbound = models.ForeignKey( - 'DataCenterAsset', - verbose_name=_('connected to device'), + "DataCenterAsset", + verbose_name=_("connected to device"), on_delete=models.PROTECT, - related_name='outbound_connections', + related_name="outbound_connections", ) inbound = models.ForeignKey( - 'DataCenterAsset', - verbose_name=_('connected device'), + "DataCenterAsset", + verbose_name=_("connected device"), on_delete=models.PROTECT, - related_name='inbound_connections', + related_name="inbound_connections", ) # TODO: discuss connection_type = models.PositiveIntegerField( - verbose_name=_('connection type'), - choices=ConnectionType() + verbose_name=_("connection type"), choices=ConnectionType() ) def __str__(self): - return '%s -> %s (%s)' % ( - self.outbound, - self.inbound, - self.connection_type - ) + return "%s -> %s (%s)" % (self.outbound, self.inbound, self.connection_type) post_commit(publish_host_update, DataCenterAsset) diff --git a/src/ralph/data_center/models/virtual.py b/src/ralph/data_center/models/virtual.py index c2fd509c7d..8fa9befffe 100644 --- a/src/ralph/data_center/models/virtual.py +++ b/src/ralph/data_center/models/virtual.py @@ -8,15 +8,12 @@ from ralph.assets.models.base import BaseObject from ralph.assets.utils import DNSaaSPublisherMixin from ralph.data_center.models.mixins import WithManagementIPMixin -from ralph.data_center.models.physical import ( - DataCenterAsset, - NetworkableBaseObject -) +from ralph.data_center.models.physical import DataCenterAsset, NetworkableBaseObject from ralph.lib.mixins.fields import BaseObjectForeignKey, NullableCharField from ralph.lib.mixins.models import ( AdminAbsoluteUrlMixin, NamedMixin, - PreviousStateMixin + PreviousStateMixin, ) from ralph.lib.transitions.fields import TransitionField from ralph.networks.models.networks import IPAddress @@ -24,34 +21,34 @@ class Database(AdminAbsoluteUrlMixin, BaseObject): class Meta: - verbose_name = _('database') - verbose_name_plural = _('databases') + verbose_name = _("database") + verbose_name_plural = _("databases") def __str__(self): - return 'Database: {}'.format(self.service_env) + return "Database: {}".format(self.service_env) class VIPProtocol(Choices): _ = Choices.Choice - TCP = _('TCP') - UDP = _('UDP') + TCP = _("TCP") + UDP = _("UDP") class VIP(AdminAbsoluteUrlMixin, BaseObject): - name = models.CharField(_('name'), max_length=255) + name = models.CharField(_("name"), max_length=255) ip = models.ForeignKey(IPAddress, on_delete=models.CASCADE) - port = models.PositiveIntegerField(verbose_name=_('port'), default=0) + port = models.PositiveIntegerField(verbose_name=_("port"), default=0) protocol = models.PositiveIntegerField( - verbose_name=_('protocol'), + verbose_name=_("protocol"), choices=VIPProtocol(), default=VIPProtocol.TCP.id, ) class Meta: - verbose_name = _('VIP') - verbose_name_plural = _('VIPs') - unique_together = ('ip', 'port', 'protocol') + verbose_name = _("VIP") + verbose_name_plural = _("VIPs") + unique_together = ("ip", "port", "protocol") def __str__(self): return "IP: {}, port: {}, protocol: {}".format( @@ -65,17 +62,17 @@ class ClusterType(AdminAbsoluteUrlMixin, NamedMixin, models.Model): show_master_summary = models.BooleanField( default=False, help_text=_( - 'show master information on cluster page, ex. hostname, model, ' - 'location etc.' - ) + "show master information on cluster page, ex. hostname, model, " + "location etc." + ), ) class ClusterStatus(Choices): _ = Choices.Choice - in_use = _('in use') - for_deploy = _('for deploy') + in_use = _("in use") + for_deploy = _("for deploy") class Cluster( @@ -85,31 +82,27 @@ class Cluster( WithManagementIPMixin, NetworkableBaseObject, BaseObject, - models.Model + models.Model, ): - name = models.CharField(_('name'), max_length=255, blank=True, null=True) + name = models.CharField(_("name"), max_length=255, blank=True, null=True) hostname = NullableCharField( - unique=True, - null=True, - blank=True, - max_length=255, - verbose_name=_('hostname') + unique=True, null=True, blank=True, max_length=255, verbose_name=_("hostname") ) type = models.ForeignKey(ClusterType, on_delete=models.CASCADE) base_objects = models.ManyToManyField( BaseObject, - verbose_name=_('Assigned base objects'), - through='BaseObjectCluster', - related_name='+', + verbose_name=_("Assigned base objects"), + through="BaseObjectCluster", + related_name="+", ) status = TransitionField( default=ClusterStatus.in_use.id, choices=ClusterStatus(), ) - previous_dc_host_update_fields = ['hostname'] + previous_dc_host_update_fields = ["hostname"] def __str__(self): - return '{} ({})'.format(self.name or self.hostname, self.type) + return "{} ({})".format(self.name or self.hostname, self.type) def get_location(self): return self.masters[0].get_location() if self.masters else [] @@ -134,7 +127,7 @@ def get_masters(self, cast_base_object=False): if cast_base_object and not isinstance( bo, # list equal to BaseObjectCluster.base_object.limit_models - (Database, DataCenterAsset, CloudHost, VirtualServer) + (Database, DataCenterAsset, CloudHost, VirtualServer), ): bo = bo.last_descendant result.append(bo) @@ -153,10 +146,8 @@ def rack(self): def _validate_name_hostname(self): if not self.name and not self.hostname: - error_message = [_('At least one of name or hostname is required')] - raise ValidationError( - {'name': error_message, 'hostname': error_message} - ) + error_message = [_("At least one of name or hostname is required")] + raise ValidationError({"name": error_message, "hostname": error_message}) def clean(self): errors = {} @@ -176,16 +167,16 @@ class BaseObjectCluster(models.Model): cluster = models.ForeignKey(Cluster, on_delete=models.CASCADE) base_object = BaseObjectForeignKey( BaseObject, - related_name='clusters', + related_name="clusters", limit_models=[ - 'data_center.Database', - 'data_center.DataCenterAsset', - 'virtual.CloudHost', - 'virtual.VirtualServer' + "data_center.Database", + "data_center.DataCenterAsset", + "virtual.CloudHost", + "virtual.VirtualServer", ], - on_delete=models.CASCADE + on_delete=models.CASCADE, ) is_master = models.BooleanField(default=False) class Meta: - unique_together = ('cluster', 'base_object') + unique_together = ("cluster", "base_object") diff --git a/src/ralph/data_center/publishers.py b/src/ralph/data_center/publishers.py index 3e24f9b35f..3ec758abc9 100644 --- a/src/ralph/data_center/publishers.py +++ b/src/ralph/data_center/publishers.py @@ -13,14 +13,16 @@ def _get_host_data(instance): from ralph.assets.api.serializers_dchosts import DCHostPhysicalSerializer from ralph.assets.api.serializers_dchosts import DCHostSerializer from ralph.data_center.models import DataCenterAsset + if isinstance(instance, DataCenterAsset): serializer = DCHostPhysicalSerializer(instance=instance) else: serializer = DCHostSerializer(instance=instance) - if hasattr(serializer.instance, '_previous_state'): + if hasattr(serializer.instance, "_previous_state"): data = deepcopy(serializer.data) - data['_previous_state'] = { - k: v for k, v in serializer.instance._previous_state.items() + data["_previous_state"] = { + k: v + for k, v in serializer.instance._previous_state.items() if k in serializer.instance.previous_dc_host_update_fields } else: @@ -29,8 +31,7 @@ def _get_host_data(instance): @pyhermes.publisher( - topic=settings.HERMES_HOST_UPDATE_TOPIC_NAME or '', - auto_publish_result=False + topic=settings.HERMES_HOST_UPDATE_TOPIC_NAME or "", auto_publish_result=False ) def publish_host_update(instance): """ @@ -38,28 +39,30 @@ def publish_host_update(instance): """ if settings.HERMES_HOST_UPDATE_TOPIC_NAME: logger.info( - 'Publishing host update for {}'.format(instance), + "Publishing host update for {}".format(instance), extra={ - 'type': 'PUBLISH_HOST_UPDATE', - 'instance_id': instance.id, - 'content_type': instance.content_type.name, - } + "type": "PUBLISH_HOST_UPDATE", + "instance_id": instance.id, + "content_type": instance.content_type.name, + }, ) host_data = _get_host_data(instance) # call publish directly to make testing easier - logger.info('Publishing DCHost update', extra={ - 'publish_data': host_data, - }) + logger.info( + "Publishing DCHost update", + extra={ + "publish_data": host_data, + }, + ) publish(settings.HERMES_HOST_UPDATE_TOPIC_NAME, host_data) def publish_host_update_from_related_model(instance, field_path): from ralph.data_center.models import DCHost - updated_instances = DCHost.objects.filter( - **{field_path: instance} + + updated_instances = DCHost.objects.filter(**{field_path: instance}) + logger.info( + "Publishing host update for {} instances".format(updated_instances.count()) ) - logger.info('Publishing host update for {} instances'.format( - updated_instances.count() - )) for instance in updated_instances: publish_host_update(instance) diff --git a/src/ralph/data_center/subscribers.py b/src/ralph/data_center/subscribers.py index 890e7ab574..99bb760241 100644 --- a/src/ralph/data_center/subscribers.py +++ b/src/ralph/data_center/subscribers.py @@ -17,20 +17,20 @@ def validate_vip_event_data(data): """Performs some basic sanity checks (e.g. missing values) on the incoming event data. Returns list of errors (if any). """ - name = data['name'] - ip = data['ip'] - port = data['port'] - protocol = data['protocol'] - service = data['service'] + name = data["name"] + ip = data["ip"] + port = data["port"] + protocol = data["protocol"] + service = data["service"] if service: - service_uid = service.get('uid') + service_uid = service.get("uid") else: service_uid = None - environment = data['environment'] + environment = data["environment"] errors = [] if not name: - err = 'missing name' + err = "missing name" errors.append(err) try: IPAddress(address=ip).clean_fields() @@ -41,13 +41,13 @@ def validate_vip_event_data(data): err = 'invalid port "{}"'.format(port) errors.append(err) if not protocol: - err = 'missing protocol' + err = "missing protocol" errors.append(err) if not service_uid: - err = 'missing service UID' + err = "missing service UID" errors.append(err) if not environment: - err = 'missing environment' + err = "missing environment" errors.append(err) return errors @@ -61,36 +61,31 @@ def get_vip(ip, port, protocol): @pyhermes.subscriber( - topic='createVipEvent', + topic="createVipEvent", ) def handle_create_vip_event(data): errors = validate_vip_event_data(data) if errors: - msg = ( - 'Error(s) detected in event data: %s. Ignoring received create ' - 'event.' - ) - logger.error(msg, '; '.join(errors)) + msg = "Error(s) detected in event data: %s. Ignoring received create " "event." + logger.error(msg, "; ".join(errors)) return # Check if VIP already exists. - ip, ip_created = IPAddress.objects.get_or_create(address=data['ip']) - protocol = VIPProtocol.from_name(data['protocol'].upper()) - vip = get_vip(ip, data['port'], protocol) + ip, ip_created = IPAddress.objects.get_or_create(address=data["ip"]) + protocol = VIPProtocol.from_name(data["protocol"].upper()) + vip = get_vip(ip, data["port"], protocol) if vip: msg = ( - 'VIP designated by IP address %s, port %s and protocol %s ' - 'already exists. Ignoring received event.' + "VIP designated by IP address %s, port %s and protocol %s " + "already exists. Ignoring received event." ) - logger.warning(msg, ip.address, data['port'], protocol.name) + logger.warning(msg, ip.address, data["port"], protocol.name) return # Create it. - cluster_type, _ = ClusterType.objects.get_or_create( - name=data['load_balancer_type'] - ) + cluster_type, _ = ClusterType.objects.get_or_create(name=data["load_balancer_type"]) cluster, _ = Cluster.objects.get_or_create( - name=data['load_balancer'], + name=data["load_balancer"], type=cluster_type, ) if ip_created: @@ -99,51 +94,54 @@ def handle_create_vip_event(data): ip.save() elif ip.dhcp_expose: logger.error( - 'Trying to create VIP with IP %s, port %s and protocol %s ' - 'failed because IP is exposed in dhcp', - ip.address, data['port'], protocol.name + "Trying to create VIP with IP %s, port %s and protocol %s " + "failed because IP is exposed in dhcp", + ip.address, + data["port"], + protocol.name, ) return try: service_env = ServiceEnvironment.objects.get( - service__uid=data['service']['uid'], - environment__name=data['environment'], + service__uid=data["service"]["uid"], + environment__name=data["environment"], ) except ServiceEnvironment.DoesNotExist: msg = ( 'ServiceEnvironment for service UID "%s" and environment "%s" ' - 'does not exist. Ignoring received create event.' + "does not exist. Ignoring received create event." ) - logger.error(msg, data['service']['uid'], data['environment']) + logger.error(msg, data["service"]["uid"], data["environment"]) return vip = VIP( - name=data['name'], + name=data["name"], ip=ip, - port=data['port'], + port=data["port"], protocol=protocol, parent=cluster, service_env=service_env, ) vip.save() - logger.debug('VIP %s created successfully.', vip.name) + logger.debug("VIP %s created successfully.", vip.name) def migrate_vip_to_cluster(vip, cluster, protocol): msg = ( - 'Trying to update VIP with IP %s, port %s and protocol %s' - 'failed: %s', (vip.ip.address, vip.port, protocol.name) + "Trying to update VIP with IP %s, port %s and protocol %s" "failed: %s", + (vip.ip.address, vip.port, protocol.name), ) cluster_content_type = ContentType.objects.get_for_model(Cluster) ethernet = vip.ip.ethernet if not ethernet: - logger.error(msg[0], *msg[1], 'no `Ethernet` object found') + logger.error(msg[0], *msg[1], "no `Ethernet` object found") return if ethernet.base_object.content_type != cluster_content_type: - logger.error(msg[0], *msg[1], - '`Ethernet` base_object is not `Cluster` instance') + logger.error( + msg[0], *msg[1], "`Ethernet` base_object is not `Cluster` instance" + ) return if vip.parent.content_type != cluster_content_type: - logger.error(msg[0], *msg[1], '`VIP` parent is not `Cluster` instance') + logger.error(msg[0], *msg[1], "`VIP` parent is not `Cluster` instance") return ethernet.base_object = cluster @@ -151,52 +149,50 @@ def migrate_vip_to_cluster(vip, cluster, protocol): vip.parent = cluster vip.save() logger.debug( - 'VIP %s with IP %s, port %s and protocol %s changed cluster to %s.', - vip.name, vip.ip.address, vip.port, protocol.name, cluster.name + "VIP %s with IP %s, port %s and protocol %s changed cluster to %s.", + vip.name, + vip.ip.address, + vip.port, + protocol.name, + cluster.name, ) @pyhermes.subscriber( - topic='updateVipEvent', + topic="updateVipEvent", ) def handle_update_vip_event(data): errors = validate_vip_event_data(data) if errors: - msg = ( - 'Error(s) detected in event data: %s. Ignoring received update ' - 'event.' - ) - logger.error(msg, '; '.join(errors)) + msg = "Error(s) detected in event data: %s. Ignoring received update " "event." + logger.error(msg, "; ".join(errors)) return - ip, _ = IPAddress.objects.get_or_create(address=data['ip']) - protocol = VIPProtocol.from_name(data['protocol'].upper()) + ip, _ = IPAddress.objects.get_or_create(address=data["ip"]) + protocol = VIPProtocol.from_name(data["protocol"].upper()) if ip.dhcp_expose: logger.error( - 'Trying to update VIP with IP %s, port %s and protocol %s ' - 'failed because IP is exposed in dhcp', - ip.address, data['port'], protocol.name + "Trying to update VIP with IP %s, port %s and protocol %s " + "failed because IP is exposed in dhcp", + ip.address, + data["port"], + protocol.name, ) return - vip = get_vip(ip, data['port'], protocol) + vip = get_vip(ip, data["port"], protocol) if vip is None: # VIP not found, should create new one. return handle_create_vip_event(data) # update cluster. - cluster_type, _ = ClusterType.objects.get_or_create( - name=data['load_balancer_type'] - ) + cluster_type, _ = ClusterType.objects.get_or_create(name=data["load_balancer_type"]) cluster, _ = Cluster.objects.get_or_create( - name=data['load_balancer'], + name=data["load_balancer"], type=cluster_type, ) - if ( - vip.parent != cluster or - (ip.ethernet and ip.ethernet.base_object != cluster) - ): + if vip.parent != cluster or (ip.ethernet and ip.ethernet.base_object != cluster): with transaction.atomic(): for migrated_vip in VIP.objects.select_for_update().filter(ip=ip): migrate_vip_to_cluster(migrated_vip, cluster, protocol) @@ -204,59 +200,52 @@ def handle_update_vip_event(data): # update service/environment if changed. try: service_env = ServiceEnvironment.objects.get( - service__uid=data['service']['uid'], - environment__name=data['environment'], + service__uid=data["service"]["uid"], + environment__name=data["environment"], ) except ServiceEnvironment.DoesNotExist: msg = ( 'ServiceEnvironment for service UID "%s" and environment "%s" ' - 'does not exist. Ignoring received update event.' + "does not exist. Ignoring received update event." ) - logger.error(msg, data['service']['uid'], data['environment']) + logger.error(msg, data["service"]["uid"], data["environment"]) return if vip.service_env != service_env: vip.service_env = service_env vip.save() - logger.debug( - 'VIP %s changed service/env to %s.', vip.name, service_env - ) + logger.debug("VIP %s changed service/env to %s.", vip.name, service_env) - logger.debug('VIP %s update processed successfully.', vip.name) + logger.debug("VIP %s update processed successfully.", vip.name) @pyhermes.subscriber( - topic='deleteVipEvent', + topic="deleteVipEvent", ) def handle_delete_vip_event(data): errors = validate_vip_event_data(data) if errors: - msg = ( - 'Error(s) detected in event data: %s. Ignoring received delete ' - 'event.' - ) - logger.error(msg, '; '.join(errors)) + msg = "Error(s) detected in event data: %s. Ignoring received delete " "event." + logger.error(msg, "; ".join(errors)) return try: - ip = IPAddress.objects.get(address=data['ip']) + ip = IPAddress.objects.get(address=data["ip"]) except IPAddress.DoesNotExist: - msg = ( - "IP address %s doesn't exist. Ignoring received delete VIP event." - ) - logger.error(msg, data['ip']) + msg = "IP address %s doesn't exist. Ignoring received delete VIP event." + logger.error(msg, data["ip"]) return - protocol = VIPProtocol.from_name(data['protocol'].upper()) - vip = get_vip(ip, data['port'], protocol) + protocol = VIPProtocol.from_name(data["protocol"].upper()) + vip = get_vip(ip, data["port"], protocol) if vip is None: msg = ( "VIP designated by IP address %s, port %s and protocol %s " "doesn't exist. Ignoring received delete event." ) - logger.warning(msg, ip.address, data['port'], protocol.name) + logger.warning(msg, ip.address, data["port"], protocol.name) return vip.delete() - logger.info('VIP %s deleted successfully.', vip.name) + logger.info("VIP %s deleted successfully.", vip.name) # Delete IP address associated with it (along with its Ethernet), but only # when this IP is not used anymore by other VIP(s). @@ -268,13 +257,13 @@ def handle_delete_vip_event(data): ip.delete() if eth_deleted: msg = ( - 'IP address %s has been deleted (along with Ethernet ' - 'associated with it) since it is no longer being used by any ' - 'VIP.' + "IP address %s has been deleted (along with Ethernet " + "associated with it) since it is no longer being used by any " + "VIP." ) else: msg = ( - 'IP address %s has been deleted since it is no longer being ' - 'used by any VIP.' + "IP address %s has been deleted since it is no longer being " + "used by any VIP." ) logger.info(msg, ip.address) diff --git a/src/ralph/data_center/tests/factories.py b/src/ralph/data_center/tests/factories.py index cbbcfc1ef0..5d4731290a 100644 --- a/src/ralph/data_center/tests/factories.py +++ b/src/ralph/data_center/tests/factories.py @@ -17,7 +17,7 @@ FibreChannelCardFactory, MemoryFactory, ProcessorFactory, - ServiceEnvironmentFactory + ServiceEnvironmentFactory, ) from ralph.data_center.models import BaseObjectCluster from ralph.data_center.models.choices import ConnectionType @@ -30,14 +30,14 @@ DataCenterAsset, Rack, RackAccessory, - ServerRoom + ServerRoom, ) from ralph.data_center.models.virtual import ( Cluster, ClusterType, Database, VIP, - VIPProtocol + VIPProtocol, ) from ralph.security.tests.factories import SecurityScanFactory @@ -45,16 +45,14 @@ class DiskShareFactory(DjangoModelFactory): - base_object = factory.SubFactory(BaseObjectFactory) - wwn = factory.Sequence(lambda n: 'wwn {}'.format(n)) + wwn = factory.Sequence(lambda n: "wwn {}".format(n)) class Meta: model = DiskShare class DiskShareMountFactory(DjangoModelFactory): - share = factory.SubFactory(DiskShareFactory) class Meta: @@ -62,16 +60,14 @@ class Meta: class ClusterTypeFactory(DjangoModelFactory): - - name = factory.Iterator(['Application', 'Partitional']) + name = factory.Iterator(["Application", "Partitional"]) class Meta: model = ClusterType - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ClusterFactory(DjangoModelFactory): - name = factory.Sequence(lambda n: f"Cluster {n}") type = factory.SubFactory(ClusterTypeFactory) configuration_path = factory.SubFactory(ConfigurationClassFactory) @@ -79,11 +75,11 @@ class ClusterFactory(DjangoModelFactory): class Meta: model = Cluster - django_get_or_create = ['name'] + django_get_or_create = ["name"] @factory.post_generation def post_tags(self, create, extracted, **kwargs): - self.tags.add('abc, cde', 'xyz') + self.tags.add("abc, cde", "xyz") class BaseObjectClusterFactory(DjangoModelFactory): @@ -92,51 +88,46 @@ class BaseObjectClusterFactory(DjangoModelFactory): class Meta: model = BaseObjectCluster - django_get_or_create = ['cluster', 'base_object'] + django_get_or_create = ["cluster", "base_object"] class DataCenterFactory(DjangoModelFactory): - - name = factory.Iterator(['DC1', 'DC2', 'DC3', 'DC4', 'DC5']) + name = factory.Iterator(["DC1", "DC2", "DC3", "DC4", "DC5"]) class Meta: model = DataCenter - django_get_or_create = ['name'] + django_get_or_create = ["name"] class ServerRoomFactory(DjangoModelFactory): - - name = factory.Iterator([ - 'Server Room A', 'Server Room B', 'Server Room C', 'Server Room D' - ]) + name = factory.Iterator( + ["Server Room A", "Server Room B", "Server Room C", "Server Room D"] + ) data_center = factory.SubFactory(DataCenterFactory) class Meta: model = ServerRoom - django_get_or_create = ['name'] + django_get_or_create = ["name"] class AccessoryFactory(DjangoModelFactory): - name = factory.Iterator(ACCESSORY_DATA) class Meta: model = Accessory - django_get_or_create = ['name'] + django_get_or_create = ["name"] class RackFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'Rack #{}'.format(n + 100)) + name = factory.Sequence(lambda n: "Rack #{}".format(n + 100)) server_room = factory.SubFactory(ServerRoomFactory) class Meta: model = Rack - django_get_or_create = ['name'] + django_get_or_create = ["name"] class RackAccessoryFactory(DjangoModelFactory): - accessory = factory.SubFactory(AccessoryFactory) rack = factory.SubFactory(RackFactory) @@ -147,25 +138,21 @@ class Meta: class DataCenterAssetFactory(DjangoModelFactory): force_depreciation = False model = factory.SubFactory(DataCenterAssetModelFactory) - sn = factory.Faker('ssn') - barcode = factory.Sequence(lambda n: 'dc' + str(n + 10**8)) - hostname = factory.Sequence(lambda n: 'ralph{}.allegro.pl'.format(n)) - order_no = factory.Sequence(lambda n: 'Order number ' + str(n)) + sn = factory.Faker("ssn") + barcode = factory.Sequence(lambda n: "dc" + str(n + 10**8)) + hostname = factory.Sequence(lambda n: "ralph{}.allegro.pl".format(n)) + order_no = factory.Sequence(lambda n: "Order number " + str(n)) budget_info = factory.SubFactory(BudgetInfoFactory) invoice_date = date_now - timedelta(days=15) - invoice_no = factory.Sequence(lambda n: 'Invoice number ' + str(n)) + invoice_no = factory.Sequence(lambda n: "Invoice number " + str(n)) property_of = factory.SubFactory(AssetHolderFactory) - provider = factory.Iterator([ - 'Komputronik', 'Dell Poland', 'Oracle Poland' - ]) - source = factory.Iterator([ - AssetSource.shipment.id, AssetSource.salvaged.id - ]) + provider = factory.Iterator(["Komputronik", "Dell Poland", "Oracle Poland"]) + source = factory.Iterator([AssetSource.shipment.id, AssetSource.salvaged.id]) price = FuzzyDecimal(10, 300) service_env = factory.SubFactory(ServiceEnvironmentFactory) configuration_path = factory.SubFactory(ConfigurationClassFactory) - firmware_version = factory.Sequence(lambda n: '1.1.{}'.format(n)) - bios_version = factory.Sequence(lambda n: '2.2.{}'.format(n)) + firmware_version = factory.Sequence(lambda n: "1.1.{}".format(n)) + bios_version = factory.Sequence(lambda n: "2.2.{}".format(n)) class Meta: model = DataCenterAsset @@ -175,6 +162,7 @@ class DataCenterAssetFullFactory(DataCenterAssetFactory): """ Factory for DataCenterAsset and m2m relations """ + rack = factory.SubFactory(RackFactory) # m2m relations @@ -182,54 +170,53 @@ class DataCenterAssetFullFactory(DataCenterAssetFactory): # clusters, tags eth1 = factory.RelatedFactory( EthernetWithIPAddressFactory, - 'base_object', + "base_object", ipaddress__is_management=True, ) - eth2 = factory.RelatedFactory(EthernetFactory, 'base_object') + eth2 = factory.RelatedFactory(EthernetFactory, "base_object") eth3 = factory.RelatedFactory( EthernetWithIPAddressFactory, - 'base_object', + "base_object", ipaddress__dhcp_expose=True, ) licence1 = factory.RelatedFactory( - 'ralph.licences.tests.factories.BaseObjectLicenceFactory', 'base_object' + "ralph.licences.tests.factories.BaseObjectLicenceFactory", "base_object" ) licence2 = factory.RelatedFactory( - 'ralph.licences.tests.factories.BaseObjectLicenceFactory', - 'base_object', - quantity=3 + "ralph.licences.tests.factories.BaseObjectLicenceFactory", + "base_object", + quantity=3, ) support1 = factory.RelatedFactory( - 'ralph.supports.tests.factories.BaseObjectsSupportFactory', - 'baseobject' + "ralph.supports.tests.factories.BaseObjectsSupportFactory", "baseobject" ) support2 = factory.RelatedFactory( - 'ralph.supports.tests.factories.BaseObjectsSupportFactory', - 'baseobject' + "ralph.supports.tests.factories.BaseObjectsSupportFactory", "baseobject" ) - mem1 = factory.RelatedFactory(MemoryFactory, 'base_object') - mem2 = factory.RelatedFactory(MemoryFactory, 'base_object') - fc_card1 = factory.RelatedFactory(FibreChannelCardFactory, 'base_object') - fc_card2 = factory.RelatedFactory(FibreChannelCardFactory, 'base_object') - proc1 = factory.RelatedFactory(ProcessorFactory, 'base_object') - proc2 = factory.RelatedFactory(ProcessorFactory, 'base_object') - disk1 = factory.RelatedFactory(DiskFactory, 'base_object') - disk2 = factory.RelatedFactory(DiskFactory, 'base_object') + mem1 = factory.RelatedFactory(MemoryFactory, "base_object") + mem2 = factory.RelatedFactory(MemoryFactory, "base_object") + fc_card1 = factory.RelatedFactory(FibreChannelCardFactory, "base_object") + fc_card2 = factory.RelatedFactory(FibreChannelCardFactory, "base_object") + proc1 = factory.RelatedFactory(ProcessorFactory, "base_object") + proc2 = factory.RelatedFactory(ProcessorFactory, "base_object") + disk1 = factory.RelatedFactory(DiskFactory, "base_object") + disk2 = factory.RelatedFactory(DiskFactory, "base_object") scmstatuscheck = factory.RelatedFactory( - 'ralph.configuration_management.tests.factories.SCMStatusCheckFactory', - 'base_object', + "ralph.configuration_management.tests.factories.SCMStatusCheckFactory", + "base_object", + ) + securityscan = factory.RelatedFactory( + SecurityScanFactory, factory_related_name="base_object" ) - securityscan = factory.RelatedFactory(SecurityScanFactory, factory_related_name='base_object') - securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object') + securityscan = factory.RelatedFactory(SecurityScanFactory, "base_object") @factory.post_generation def post_tags(self, create, extracted, **kwargs): - self.tags.add('abc, cde', 'xyz') + self.tags.add("abc, cde", "xyz") class ConnectionFactory(DjangoModelFactory): - outbound = factory.SubFactory(DataCenterAssetFactory) inbound = factory.SubFactory(DataCenterAssetFactory) connection_type = factory.Iterator([ConnectionType.network.id]) @@ -246,9 +233,9 @@ class Meta: class VIPFactory(DjangoModelFactory): - name = factory.Sequence(lambda n: 'ralph-test{}.local'.format(n)) + name = factory.Sequence(lambda n: "ralph-test{}.local".format(n)) # IPAddressFactory is given as string to avoid circular imports here. - ip = factory.SubFactory('ralph.networks.tests.factories.IPAddressFactory') + ip = factory.SubFactory("ralph.networks.tests.factories.IPAddressFactory") port = FuzzyInteger(1024, 49151) protocol = factory.Iterator([VIPProtocol.TCP.id, VIPProtocol.UDP.id]) service_env = factory.SubFactory(ServiceEnvironmentFactory) diff --git a/src/ralph/data_center/tests/test_admin.py b/src/ralph/data_center/tests/test_admin.py index 515b137ee5..46b87bec4a 100644 --- a/src/ralph/data_center/tests/test_admin.py +++ b/src/ralph/data_center/tests/test_admin.py @@ -6,19 +6,13 @@ from django.test import override_settings, RequestFactory, TransactionTestCase from ralph.accounts.tests.factories import UserFactory -from ralph.assets.tests.factories import ( - ServiceEnvironmentFactory, - ServiceFactory -) +from ralph.assets.tests.factories import ServiceEnvironmentFactory, ServiceFactory from ralph.data_center.models import DataCenterAsset -from ralph.data_center.tests.factories import ( - DataCenterAssetFactory, - RackFactory -) +from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue + CustomFieldValue, ) @@ -27,42 +21,42 @@ class DataCenterAssetAdminTest(TransactionTestCase): def setUp(self): self.user = get_user_model().objects.create_superuser( - username='root', - password='password', - email='email@email.pl' + username="root", password="password", email="email@email.pl" ) - result = self.client.login(username='root', password='password') + result = self.client.login(username="root", password="password") self.assertEqual(result, True) self.factory = RequestFactory() self.dca = DataCenterAssetFactory( - hostname='ralph1.allegro.pl', - rack=RackFactory(), - position=1 + hostname="ralph1.allegro.pl", rack=RackFactory(), position=1 + ) + self.custom_fields_inline_prefix = ( + "custom_fields-customfieldvalue-content_type-object_id-" # noqa ) - self.custom_fields_inline_prefix = 'custom_fields-customfieldvalue-content_type-object_id-' # noqa self.custom_field_str = CustomField.objects.create( - name='test_str', type=CustomFieldTypes.STRING, default_value='xyz' + name="test_str", type=CustomFieldTypes.STRING, default_value="xyz" ) self.custom_field_choices = CustomField.objects.create( - name='test_choice', type=CustomFieldTypes.CHOICE, - choices='qwerty|asdfgh|zxcvbn', default_value='zxcvbn', + name="test_choice", + type=CustomFieldTypes.CHOICE, + choices="qwerty|asdfgh|zxcvbn", + default_value="zxcvbn", use_as_configuration_variable=True, ) def _update_dca(self, dca_data=None, inline_data=None): data = { - 'id': self.dca.id, - 'sn': self.dca.sn, - 'barcode': self.dca.barcode, - 'hostname': self.dca.hostname, - 'model': self.dca.model_id, - 'orientation': self.dca.orientation, - 'rack': self.dca.rack.pk, - 'position': self.dca.position, - 'service_env': self.dca.service_env_id, - 'status': self.dca.status, - 'depreciation_rate': self.dca.depreciation_rate, - 'property_of': self.dca.property_of.id + "id": self.dca.id, + "sn": self.dca.sn, + "barcode": self.dca.barcode, + "hostname": self.dca.hostname, + "model": self.dca.model_id, + "orientation": self.dca.orientation, + "rack": self.dca.rack.pk, + "position": self.dca.position, + "service_env": self.dca.service_env_id, + "status": self.dca.status, + "depreciation_rate": self.dca.depreciation_rate, + "property_of": self.dca.property_of.id, } data.update(dca_data or {}) if inline_data: @@ -72,124 +66,122 @@ def _update_dca(self, dca_data=None, inline_data=None): response.status_code, 302, ( - repr(response.context['form'].errors) - if response.context and 'form' in response.context else '' - ) + repr(response.context["form"].errors) + if response.context and "form" in response.context + else "" + ), ) def _prepare_inline_data(self, d): return { - '{}{}'.format(self.custom_fields_inline_prefix, k): v + "{}{}".format(self.custom_fields_inline_prefix, k): v for (k, v) in d.items() } def test_if_mail_notification_is_send_when_dca_is_updated_through_gui(self): - old_service = ServiceFactory(name='test') - new_service = ServiceFactory(name='prod') - old_service.business_owners.add(UserFactory(email='test1@test.pl')) - new_service.business_owners.add(UserFactory(email='test2@test.pl')) + old_service = ServiceFactory(name="test") + new_service = ServiceFactory(name="prod") + old_service.business_owners.add(UserFactory(email="test1@test.pl")) + new_service.business_owners.add(UserFactory(email="test2@test.pl")) old_service_env = ServiceEnvironmentFactory(service=old_service) new_service_env = ServiceEnvironmentFactory(service=new_service) # update without triggering signals - DataCenterAsset.objects.filter( - pk=self.dca.pk - ).update(service_env=old_service_env) + DataCenterAsset.objects.filter(pk=self.dca.pk).update( + service_env=old_service_env + ) data_custom_fields = { - 'TOTAL_FORMS': 3, - 'INITIAL_FORMS': 0, + "TOTAL_FORMS": 3, + "INITIAL_FORMS": 0, } self._update_dca( - dca_data={'service_env': new_service_env.id}, - inline_data=data_custom_fields + dca_data={"service_env": new_service_env.id}, inline_data=data_custom_fields ) self.dca.refresh_from_db() self.assertEqual(len(mail.outbox), 1) self.assertEqual( - 'Device has been assigned to Service: {} ({})'.format( + "Device has been assigned to Service: {} ({})".format( new_service, self.dca ), - mail.outbox[0].subject - ) - self.assertCountEqual( - mail.outbox[0].to, - ['test1@test.pl', 'test2@test.pl'] + mail.outbox[0].subject, ) + self.assertCountEqual(mail.outbox[0].to, ["test1@test.pl", "test2@test.pl"]) - @override_settings(HERMES_HOST_UPDATE_TOPIC_NAME='ralph.host_update') - @mock.patch('ralph.data_center.publishers.publish') + @override_settings(HERMES_HOST_UPDATE_TOPIC_NAME="ralph.host_update") + @mock.patch("ralph.data_center.publishers.publish") def test_if_host_update_is_published_to_hermes_when_dca_is_updated_through_gui( # noqa: E501 self, publish_mock ): self.cfv1 = CustomFieldValue.objects.create( object=self.dca, custom_field=self.custom_field_str, - value='sample_value', + value="sample_value", ) - new_service = ServiceFactory(name='service1', uid='sc-44444') + new_service = ServiceFactory(name="service1", uid="sc-44444") new_service_env = ServiceEnvironmentFactory( - service=new_service, environment__name='dev' + service=new_service, environment__name="dev" ) data_custom_fields = { - 'TOTAL_FORMS': 3, - 'INITIAL_FORMS': 1, - '0-id': self.cfv1.id, - '0-custom_field': self.custom_field_str.id, - '0-value': 'sample_value22', - '1-id': '', - '1-custom_field': self.custom_field_choices.id, - '1-value': 'qwerty', + "TOTAL_FORMS": 3, + "INITIAL_FORMS": 1, + "0-id": self.cfv1.id, + "0-custom_field": self.custom_field_str.id, + "0-value": "sample_value22", + "1-id": "", + "1-custom_field": self.custom_field_choices.id, + "1-value": "qwerty", } with transaction.atomic(): self._update_dca( dca_data={ - 'service_env': new_service_env.id, - 'hostname': 'my-host.mydc.net', + "service_env": new_service_env.id, + "hostname": "my-host.mydc.net", }, - inline_data=data_custom_fields + inline_data=data_custom_fields, ) # DCA is saved twice self.assertGreater(len(connection.run_on_commit), 0) self.dca.refresh_from_db() publish_data = publish_mock.call_args[0][1] - publish_data.pop('modified') - publish_data.pop('created') - self.assertCountEqual(publish_data, { - '__str__': 'data center asset: ' + str(self.dca), - 'configuration_path': None, - 'configuration_variables': { - 'test_choice': 'qwerty', - }, - 'custom_fields': { - 'test_str': 'sample_value22', - 'test_choice': 'qwerty' - }, - 'ethernet': [], - 'hostname': 'my-host.mydc.net', - 'id': self.dca.id, - 'model': str(self.dca.model), - 'ipaddresses': [], - 'object_type': 'datacenterasset', - 'parent': None, - 'remarks': '', - 'service_env': { - 'id': new_service_env.id, - 'service': 'service1', - 'environment': 'dev', - 'service_uid': 'sc-44444', - 'ui_url': '' - }, - 'tags': [], - 'securityscan': None, - '_previous_state': { - 'hostname': 'ralph1.allegro.pl' + publish_data.pop("modified") + publish_data.pop("created") + self.assertCountEqual( + publish_data, + { + "__str__": "data center asset: " + str(self.dca), + "configuration_path": None, + "configuration_variables": { + "test_choice": "qwerty", + }, + "custom_fields": { + "test_str": "sample_value22", + "test_choice": "qwerty", + }, + "ethernet": [], + "hostname": "my-host.mydc.net", + "id": self.dca.id, + "model": str(self.dca.model), + "ipaddresses": [], + "object_type": "datacenterasset", + "parent": None, + "remarks": "", + "service_env": { + "id": new_service_env.id, + "service": "service1", + "environment": "dev", + "service_uid": "sc-44444", + "ui_url": "", + }, + "tags": [], + "securityscan": None, + "_previous_state": {"hostname": "ralph1.allegro.pl"}, + "ui_url": "", }, - 'ui_url': '' - }) + ) # Despite `save` is called twice, publish update data is called only # once self.assertEqual(publish_mock.call_count, 1) diff --git a/src/ralph/data_center/tests/test_api.py b/src/ralph/data_center/tests/test_api.py index cc55da1f85..c84a455fc8 100644 --- a/src/ralph/data_center/tests/test_api.py +++ b/src/ralph/data_center/tests/test_api.py @@ -7,7 +7,7 @@ AssetHolderFactory, DataCenterAssetModelFactory, EthernetFactory, - ServiceEnvironmentFactory + ServiceEnvironmentFactory, ) from ralph.data_center.models import ( BaseObjectCluster, @@ -16,7 +16,7 @@ Orientation, Rack, RackAccessory, - RackOrientation + RackOrientation, ) from ralph.data_center.tests.factories import ( AccessoryFactory, @@ -26,7 +26,7 @@ DataCenterAssetFullFactory, RackAccessoryFactory, RackFactory, - ServerRoomFactory + ServerRoomFactory, ) from ralph.networks.tests.factories import IPAddressFactory @@ -44,375 +44,329 @@ def setUp(self): rack=self.rack, position=10, model=self.model, - service_env__environment__name='some_env' + service_env__environment__name="some_env", ) self.dc_asset.service_env.service.business_owners.set([self.user1]) self.dc_asset.service_env.service.technical_owners.set([self.user2]) - self.ip = IPAddressFactory( - ethernet=EthernetFactory(base_object=self.dc_asset) - ) - self.dc_asset.tags.add('db', 'test') + self.ip = IPAddressFactory(ethernet=EthernetFactory(base_object=self.dc_asset)) + self.dc_asset.tags.add("db", "test") self.dc_asset_2 = DataCenterAssetFullFactory(rack=self.rack) def test_get_data_center_assets_list(self): DataCenterAssetFullFactory.create_batch(100) - url = reverse('datacenterasset-list') + "?limit=100" + url = reverse("datacenterasset-list") + "?limit=100" with self.assertNumQueries(21): - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], DataCenterAsset.objects.count() - ) + self.assertEqual(response.data["count"], DataCenterAsset.objects.count()) def test_get_data_center_asset_details(self): - url = reverse('datacenterasset-detail', args=(self.dc_asset.id,)) - response = self.client.get(url, format='json') + url = reverse("datacenterasset-detail", args=(self.dc_asset.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['hostname'], self.dc_asset.hostname) - self.assertEqual( - response.data['rack']['id'], self.dc_asset.rack.id - ) - self.assertEqual( - response.data['model']['id'], self.dc_asset.model.id - ) - self.assertEqual(len(response.data['ethernet']), 4) - self.assertIn(self.ip.address, [ - eth['ipaddress']['address'] for eth in response.data['ethernet'] - if eth['ipaddress'] - ]) - self.assertEqual(len(response.data['memory']), 2) - self.assertEqual(response.data['memory'][0]['speed'], 1600) - self.assertEqual(response.data['memory'][0]['size'], 8192) - self.assertEqual( - response.data['business_owners'][0]['username'], 'user1' - ) - self.assertEqual( - response.data['technical_owners'][0]['username'], 'user2' - ) + self.assertEqual(response.data["hostname"], self.dc_asset.hostname) + self.assertEqual(response.data["rack"]["id"], self.dc_asset.rack.id) + self.assertEqual(response.data["model"]["id"], self.dc_asset.model.id) + self.assertEqual(len(response.data["ethernet"]), 4) + self.assertIn( + self.ip.address, + [ + eth["ipaddress"]["address"] + for eth in response.data["ethernet"] + if eth["ipaddress"] + ], + ) + self.assertEqual(len(response.data["memory"]), 2) + self.assertEqual(response.data["memory"][0]["speed"], 1600) + self.assertEqual(response.data["memory"][0]["size"], 8192) + self.assertEqual(response.data["business_owners"][0]["username"], "user1") + self.assertEqual(response.data["technical_owners"][0]["username"], "user2") def test_get_data_center_asset_details_related_hosts(self): dc_asset_3 = DataCenterAssetFullFactory() - cloud_host = CloudHostFactory( - hypervisor=dc_asset_3 - ) - virtual_server = VirtualServerFactory( - parent=dc_asset_3 - ) + cloud_host = CloudHostFactory(hypervisor=dc_asset_3) + virtual_server = VirtualServerFactory(parent=dc_asset_3) virtual_server_2 = VirtualServerFactory( - parent=dc_asset_3, - hostname='random_test_hostname' - ) - dc_asset_4 = DataCenterAssetFullFactory( - parent=dc_asset_3 - ) - url = reverse('datacenterasset-detail', args=(dc_asset_3.id,)) - response = self.client.get(url, format='json') - self.assertEqual( - len(response.data['related_hosts']['cloud_hosts']), 1 - ) - self.assertEqual( - len(response.data['related_hosts']['virtual_servers']), 2 + parent=dc_asset_3, hostname="random_test_hostname" ) + dc_asset_4 = DataCenterAssetFullFactory(parent=dc_asset_3) + url = reverse("datacenterasset-detail", args=(dc_asset_3.id,)) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["related_hosts"]["cloud_hosts"]), 1) + self.assertEqual(len(response.data["related_hosts"]["virtual_servers"]), 2) self.assertIn( - response.data['related_hosts']['virtual_servers'][0]['hostname'], - (virtual_server.hostname, virtual_server_2.hostname) + response.data["related_hosts"]["virtual_servers"][0]["hostname"], + (virtual_server.hostname, virtual_server_2.hostname), ) self.assertIn( - response.data['related_hosts']['virtual_servers'][1]['hostname'], - (virtual_server.hostname, virtual_server_2.hostname) - ) - self.assertEqual( - response.data['related_hosts']['cloud_hosts'][0]['hostname'], - cloud_host.hostname + response.data["related_hosts"]["virtual_servers"][1]["hostname"], + (virtual_server.hostname, virtual_server_2.hostname), ) self.assertEqual( - len(response.data['related_hosts']['physical_servers']), 1 + response.data["related_hosts"]["cloud_hosts"][0]["hostname"], + cloud_host.hostname, ) + self.assertEqual(len(response.data["related_hosts"]["physical_servers"]), 1) self.assertEqual( - response.data['related_hosts']['physical_servers'][0]['hostname'], - dc_asset_4.hostname + response.data["related_hosts"]["physical_servers"][0]["hostname"], + dc_asset_4.hostname, ) + def test_get_data_center_asset_list_related_hosts(self): dc_asset_5 = DataCenterAssetFullFactory() - cloud_host = CloudHostFactory( - hypervisor=dc_asset_5 - ) - virtual_server = VirtualServerFactory( - parent=dc_asset_5 - ) + cloud_host = CloudHostFactory(hypervisor=dc_asset_5) + virtual_server = VirtualServerFactory(parent=dc_asset_5) virtual_server_2 = VirtualServerFactory( - parent=dc_asset_5, - hostname='random_test_hostname' - ) - dc_asset_6 = DataCenterAssetFullFactory( - parent=dc_asset_5 + parent=dc_asset_5, hostname="random_test_hostname" ) + dc_asset_6 = DataCenterAssetFullFactory(parent=dc_asset_5) url = f"{reverse('datacenterasset-list')}?hostname={dc_asset_5.hostname}" - response = self.client.get(url, format='json') - self.assertEqual( - len(response.data['results']), 1 - ) + response = self.client.get(url, format="json") + self.assertEqual(len(response.data["results"]), 1) self.assertEqual( - len(response.data['results'][0]['related_hosts']['cloud_hosts']), 1 + len(response.data["results"][0]["related_hosts"]["cloud_hosts"]), 1 ) self.assertEqual( - len(response.data['results'][0]['related_hosts']['virtual_servers']), 2 + len(response.data["results"][0]["related_hosts"]["virtual_servers"]), 2 ) self.assertIn( - response.data['results'][0]['related_hosts']['virtual_servers'][0]['hostname'], - (virtual_server.hostname, virtual_server_2.hostname) + response.data["results"][0]["related_hosts"]["virtual_servers"][0][ + "hostname" + ], + (virtual_server.hostname, virtual_server_2.hostname), ) self.assertIn( - response.data['results'][0]['related_hosts']['virtual_servers'][1]['hostname'], - (virtual_server.hostname, virtual_server_2.hostname) + response.data["results"][0]["related_hosts"]["virtual_servers"][1][ + "hostname" + ], + (virtual_server.hostname, virtual_server_2.hostname), ) self.assertEqual( - response.data['results'][0]['related_hosts']['cloud_hosts'][0]['hostname'], - cloud_host.hostname + response.data["results"][0]["related_hosts"]["cloud_hosts"][0]["hostname"], + cloud_host.hostname, ) self.assertEqual( - len(response.data['results'][0]['related_hosts']['physical_servers']), 1 + len(response.data["results"][0]["related_hosts"]["physical_servers"]), 1 ) self.assertEqual( - response.data['results'][0]['related_hosts']['physical_servers'][0]['hostname'], - dc_asset_6.hostname + response.data["results"][0]["related_hosts"]["physical_servers"][0][ + "hostname" + ], + dc_asset_6.hostname, ) def test_create_data_center_asset(self): - url = reverse('datacenterasset-list') + url = reverse("datacenterasset-list") data = { - 'hostname': '12345', - 'barcode': '12345', - 'model': self.model.id, - 'rack': self.rack.id, - 'position': 12, - 'service_env': self.service_env.id, - 'force_depreciation': False, - 'property_of': self.assetHolder.id, + "hostname": "12345", + "barcode": "12345", + "model": self.model.id, + "rack": self.rack.id, + "position": 12, + "service_env": self.service_env.id, + "force_depreciation": False, + "property_of": self.assetHolder.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - dc_asset = DataCenterAsset.objects.get(pk=response.data['id']) - self.assertEqual(dc_asset.hostname, '12345') + dc_asset = DataCenterAsset.objects.get(pk=response.data["id"]) + self.assertEqual(dc_asset.hostname, "12345") self.assertEqual(dc_asset.service_env, self.service_env) self.assertEqual(dc_asset.rack, self.rack) def test_create_data_center_asset_without_rack(self): - url = reverse('datacenterasset-list') + url = reverse("datacenterasset-list") data = { - 'hostname': '12345', - 'barcode': '12345', - 'model': self.model.id, - 'position': 12, - 'service_env': self.service_env.id, - 'force_depreciation': False, + "hostname": "12345", + "barcode": "12345", + "model": self.model.id, + "position": 12, + "service_env": self.service_env.id, + "force_depreciation": False, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, { - 'rack': ['This field is required.'], - }) + self.assertEqual( + response.data, + { + "rack": ["This field is required."], + }, + ) def test_create_data_center_asset_with_rack_null(self): - url = reverse('datacenterasset-list') + url = reverse("datacenterasset-list") data = { - 'hostname': '12345', - 'barcode': '12345', - 'rack': None, - 'model': self.model.id, - 'position': 12, - 'service_env': self.service_env.id, - 'force_depreciation': False, + "hostname": "12345", + "barcode": "12345", + "rack": None, + "model": self.model.id, + "position": 12, + "service_env": self.service_env.id, + "force_depreciation": False, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, { - 'rack': ['This field may not be null.'], - }) + self.assertEqual( + response.data, + { + "rack": ["This field may not be null."], + }, + ) def test_create_data_center_with_tags(self): - url = reverse('datacenterasset-list') + url = reverse("datacenterasset-list") data = { - 'hostname': '12345', - 'barcode': '12345', - 'model': self.model.id, - 'rack': self.rack.id, - 'position': 12, - 'service_env': self.service_env.id, - 'force_depreciation': False, - 'tags': ['prod', 'db'], - 'property_of': self.assetHolder.id, + "hostname": "12345", + "barcode": "12345", + "model": self.model.id, + "rack": self.rack.id, + "position": 12, + "service_env": self.service_env.id, + "force_depreciation": False, + "tags": ["prod", "db"], + "property_of": self.assetHolder.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - dc_asset = DataCenterAsset.objects.get(pk=response.data['id']) - self.assertEqual(dc_asset.hostname, '12345') + dc_asset = DataCenterAsset.objects.get(pk=response.data["id"]) + self.assertEqual(dc_asset.hostname, "12345") self.assertEqual(dc_asset.service_env, self.service_env) self.assertEqual(dc_asset.rack, self.rack) self.assertEqual(dc_asset.tags.count(), 2) def test_create_data_center_without_barcode_and_sn(self): - url = reverse('datacenterasset-list') + url = reverse("datacenterasset-list") data = { - 'hostname': '12345', - 'model': self.model.id, - 'rack': self.rack.id, - 'position': 12, - 'service_env': self.service_env.id, - 'force_depreciation': False, - 'tags': ['prod', 'db'], - 'property_of': self.assetHolder.id + "hostname": "12345", + "model": self.model.id, + "rack": self.rack.id, + "position": 12, + "service_env": self.service_env.id, + "force_depreciation": False, + "tags": ["prod", "db"], + "property_of": self.assetHolder.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, { - 'sn': ['SN or BARCODE field is required'], - 'barcode': ['SN or BARCODE field is required'], - }) - + self.assertEqual( + response.data, + { + "sn": ["SN or BARCODE field is required"], + "barcode": ["SN or BARCODE field is required"], + }, + ) def test_create_data_center_without_property_of(self): - url = reverse('datacenterasset-list') + url = reverse("datacenterasset-list") data = { - 'hostname': '12345', - 'model': self.model.id, - 'rack': self.rack.id, - 'position': 12, - 'service_env': self.service_env.id, - 'force_depreciation': False, - 'tags': ['prod', 'db'], - 'sn': 'sn', + "hostname": "12345", + "model": self.model.id, + "rack": self.rack.id, + "position": 12, + "service_env": self.service_env.id, + "force_depreciation": False, + "tags": ["prod", "db"], + "sn": "sn", } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, { - '__all__': ['Property of field is required'], - }) + self.assertEqual( + response.data, + { + "__all__": ["Property of field is required"], + }, + ) def test_patch_data_center_asset(self): - url = reverse('datacenterasset-detail', args=(self.dc_asset.id,)) - data = { - 'hostname': '54321', - 'force_depreciation': True, - 'tags': ['net'] - } - response = self.client.patch(url, data, format='json') + url = reverse("datacenterasset-detail", args=(self.dc_asset.id,)) + data = {"hostname": "54321", "force_depreciation": True, "tags": ["net"]} + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.hostname, '54321') + self.assertEqual(self.dc_asset.hostname, "54321") self.assertTrue(self.dc_asset.force_depreciation) self.assertEqual(self.dc_asset.tags.count(), 1) def test_update_vendor_contract_number_and_leasing_rate(self): - url = reverse('datacenterasset-detail', args=(self.dc_asset.id,)) + url = reverse("datacenterasset-detail", args=(self.dc_asset.id,)) hostname = self.dc_asset.hostname - data = { - 'vendor_contract_number': 'abc-123', - 'leasing_rate': 123.45 - } - response = self.client.patch(url, data, format='json') + data = {"vendor_contract_number": "abc-123", "leasing_rate": 123.45} + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.dc_asset.refresh_from_db() self.assertEqual(self.dc_asset.hostname, hostname) - self.assertEqual(self.dc_asset.vendor_contract_number, 'abc-123') + self.assertEqual(self.dc_asset.vendor_contract_number, "abc-123") self.assertEqual(self.dc_asset.leasing_rate, 123.45) def test_filter_by_configuration_path(self): - url = reverse('datacenterasset-list') + '?configuration_path={}'.format( + url = reverse("datacenterasset-list") + "?configuration_path={}".format( self.dc_asset.configuration_path.path, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_hostname(self): - url = reverse('datacenterasset-list') + '?hostname={}'.format( + url = reverse("datacenterasset-list") + "?hostname={}".format( self.dc_asset.hostname, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_ip_address(self): - url = reverse('datacenterasset-list') + '?ip={}'.format( + url = reverse("datacenterasset-list") + "?ip={}".format( self.ip.address, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_uid(self): - url = reverse('datacenterasset-list') + '?service={}'.format( + url = reverse("datacenterasset-list") + "?service={}".format( self.dc_asset.service_env.service.uid, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_uid2(self): - url = ( - reverse('datacenterasset-list') + - '?service_env__service__uid={}'.format( - self.dc_asset.service_env.service.uid, - ) + url = reverse("datacenterasset-list") + "?service_env__service__uid={}".format( + self.dc_asset.service_env.service.uid, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_id(self): - url = ( - reverse('datacenterasset-list') + - '?service_env__service__id={}'.format( - self.dc_asset.service_env.service.id, - ) + url = reverse("datacenterasset-list") + "?service_env__service__id={}".format( + self.dc_asset.service_env.service.id, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_name(self): - url = reverse('datacenterasset-list') + '?service={}'.format( + url = reverse("datacenterasset-list") + "?service={}".format( self.dc_asset.service_env.service.name, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_name2(self): - url = ( - reverse('datacenterasset-list') + - '?service_env__service__name={}'.format( - self.dc_asset.service_env.service.name, - ) + url = reverse("datacenterasset-list") + "?service_env__service__name={}".format( + self.dc_asset.service_env.service.name, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_env_name(self): - url = reverse('datacenterasset-list') + '?env=some_env' - response = self.client.get(url, format='json') + url = reverse("datacenterasset-list") + "?env=some_env" + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) class RackAPITests(RalphAPITestCase): @@ -426,71 +380,67 @@ def setUp(self): ) def test_get_rack_list(self): - url = reverse('rack-list') - response = self.client.get(url, format='json') + url = reverse("rack-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], Rack.objects.count() - ) + self.assertEqual(response.data["count"], Rack.objects.count()) def test_get_rack_details(self): - url = reverse('rack-detail', args=(self.rack.id,)) - response = self.client.get(url, format='json') + url = reverse("rack-detail", args=(self.rack.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.rack.name) - self.assertEqual( - response.data['server_room']['id'], self.server_room.id - ) + self.assertEqual(response.data["name"], self.rack.name) + self.assertEqual(response.data["server_room"]["id"], self.server_room.id) self.assertEqual( - response.data['server_room']['data_center']['id'], - self.server_room.data_center.id + response.data["server_room"]["data_center"]["id"], + self.server_room.data_center.id, ) - accessory = response.data['accessories'][0] - self.assertEqual(accessory['id'], self.rack_accessory.id) - self.assertEqual(accessory['name'], self.rack_accessory.accessory.name) - self.assertEqual(accessory['position'], self.rack_accessory.position) + accessory = response.data["accessories"][0] + self.assertEqual(accessory["id"], self.rack_accessory.id) + self.assertEqual(accessory["name"], self.rack_accessory.accessory.name) + self.assertEqual(accessory["position"], self.rack_accessory.position) def test_create_rack(self): - url = reverse('rack-list') + url = reverse("rack-list") data = { - 'name': 'Rack 111', - 'server_room': self.server_room.id, - 'description': 'My rack', - 'orientation': 'bottom', + "name": "Rack 111", + "server_room": self.server_room.id, + "description": "My rack", + "orientation": "bottom", } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - rack = Rack.objects.get(pk=response.data['id']) - self.assertEqual(rack.name, 'Rack 111') + rack = Rack.objects.get(pk=response.data["id"]) + self.assertEqual(rack.name, "Rack 111") self.assertEqual(rack.server_room, self.server_room) - self.assertEqual(rack.description, 'My rack') + self.assertEqual(rack.description, "My rack") self.assertEqual(rack.orientation, RackOrientation.bottom) def test_create_rack_skip_accessories(self): # accessories should be created directly by RackAccessory - not assigned # by rack since it's m2m with through table - url = reverse('rack-list') + url = reverse("rack-list") data = { - 'name': 'Rack 111', - 'server_room': self.server_room.id, - 'accessories': [self.accessory.id], + "name": "Rack 111", + "server_room": self.server_room.id, + "accessories": [self.accessory.id], } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - rack = Rack.objects.get(pk=response.data['id']) + rack = Rack.objects.get(pk=response.data["id"]) self.assertEqual(rack.accessories.count(), 0) def test_patch_rack(self): - url = reverse('rack-detail', args=(self.rack.id,)) + url = reverse("rack-detail", args=(self.rack.id,)) data = { - 'name': 'Rack 222', - 'description': 'qwerty', + "name": "Rack 222", + "description": "qwerty", } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.rack.refresh_from_db() - self.assertEqual(self.rack.name, 'Rack 222') - self.assertEqual(self.rack.description, 'qwerty') + self.assertEqual(self.rack.name, "Rack 222") + self.assertEqual(self.rack.description, "qwerty") class RackAccessoryAPITests(RalphAPITestCase): @@ -504,62 +454,59 @@ def setUp(self): ) def test_get_rack_accessory_list(self): - url = reverse('rackaccessory-list') - response = self.client.get(url, format='json') + url = reverse("rackaccessory-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], RackAccessory.objects.count() - ) + self.assertEqual(response.data["count"], RackAccessory.objects.count()) def test_get_rack_accessory_details(self): - url = reverse('rackaccessory-detail', args=(self.rack_accessory.id,)) - response = self.client.get(url, format='json') + url = reverse("rackaccessory-detail", args=(self.rack_accessory.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue( - response.data['rack'].endswith( - reverse('rack-detail', args=(self.rack_accessory.rack.id,)) + response.data["rack"].endswith( + reverse("rack-detail", args=(self.rack_accessory.rack.id,)) ) ) self.assertTrue( - response.data['accessory'].endswith( - reverse( - 'accessory-detail', args=(self.rack_accessory.accessory.id,) - ) + response.data["accessory"].endswith( + reverse("accessory-detail", args=(self.rack_accessory.accessory.id,)) ) ) self.assertEqual( - response.data['orientation'], - Orientation.name_from_id(self.rack_accessory.orientation) + response.data["orientation"], + Orientation.name_from_id(self.rack_accessory.orientation), ) self.assertEqual( - response.data['position'], self.rack_accessory.position, + response.data["position"], + self.rack_accessory.position, ) def test_create_rack_accessory(self): - url = reverse('rackaccessory-list') + url = reverse("rackaccessory-list") data = { - 'rack': self.rack.id, - 'accessory': self.accessory.id, - 'orientation': 'front', - 'position': 11, + "rack": self.rack.id, + "accessory": self.accessory.id, + "orientation": "front", + "position": 11, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - rack_accessory = RackAccessory.objects.get(pk=response.data['id']) + rack_accessory = RackAccessory.objects.get(pk=response.data["id"]) self.assertEqual(rack_accessory.rack, self.rack) self.assertEqual(rack_accessory.accessory, self.accessory) self.assertEqual(rack_accessory.orientation, Orientation.front.id) self.assertEqual(rack_accessory.position, 11) def test_patch_rack_accessory(self): - url = reverse('rackaccessory-detail', args=(self.rack_accessory.id,)) + url = reverse("rackaccessory-detail", args=(self.rack_accessory.id,)) data = { - 'remarks': 'qwerty', + "remarks": "qwerty", } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.rack_accessory.refresh_from_db() - self.assertEqual(self.rack_accessory.remarks, 'qwerty') + self.assertEqual(self.rack_accessory.remarks, "qwerty") class ClusterAPITests(RalphAPITestCase): @@ -573,112 +520,105 @@ def setUp(self): ) self.master = DataCenterAssetFactory() self.boc_2 = BaseObjectCluster.objects.create( - cluster=self.cluster_1, base_object=self.master, - is_master=True + cluster=self.cluster_1, base_object=self.master, is_master=True ) self.cluster_2 = ClusterFactory() self.cluster_1.service_env.service.business_owners.set([self.user1]) self.cluster_1.service_env.service.technical_owners.set([self.user2]) - self.cluster_1.management_ip = '10.20.30.40' + self.cluster_1.management_ip = "10.20.30.40" def test_create_cluster(self): - url = reverse('cluster-list') + url = reverse("cluster-list") data = { - 'type': self.cluster_type.id, - 'service_env': self.service_env.id, - 'name': 'Test cluster' + "type": self.cluster_type.id, + "service_env": self.service_env.id, + "name": "Test cluster", } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - cluster = Cluster.objects.get(pk=response.data['id']) - self.assertEqual(cluster.name, 'Test cluster') + cluster = Cluster.objects.get(pk=response.data["id"]) + self.assertEqual(cluster.name, "Test cluster") def test_create_cluster_with_hostname(self): - url = reverse('cluster-list') + url = reverse("cluster-list") data = { - 'type': self.cluster_type.id, - 'service_env': self.service_env.id, - 'hostname': 'cluster1.mydc.net' + "type": self.cluster_type.id, + "service_env": self.service_env.id, + "hostname": "cluster1.mydc.net", } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - cluster = Cluster.objects.get(pk=response.data['id']) - self.assertEqual(cluster.hostname, data['hostname']) + cluster = Cluster.objects.get(pk=response.data["id"]) + self.assertEqual(cluster.hostname, data["hostname"]) def test_create_cluster_without_hostname_or_name(self): - url = reverse('cluster-list') + url = reverse("cluster-list") data = { - 'type': self.cluster_type.id, - 'service_env': self.service_env.id, + "type": self.cluster_type.id, + "service_env": self.service_env.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, { - 'name': ['At least one of name or hostname is required'], - 'hostname': ['At least one of name or hostname is required'], - }) + self.assertEqual( + response.data, + { + "name": ["At least one of name or hostname is required"], + "hostname": ["At least one of name or hostname is required"], + }, + ) def test_list_cluster(self): ClusterFactory.create_batch(20) - url = reverse('cluster-list') + "?limit=100" + url = reverse("cluster-list") + "?limit=100" with self.assertNumQueries(13): - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data['results']), 22) - for item in response.data['results']: - if item['id'] == self.cluster_1.id: - self.assertEqual(len(item['base_objects']), 2) + self.assertEqual(len(response.data["results"]), 22) + for item in response.data["results"]: + if item["id"] == self.cluster_1.id: + self.assertEqual(len(item["base_objects"]), 2) def test_get_cluster_details(self): - url = reverse('cluster-detail', args=(self.cluster_1.id,)) + url = reverse("cluster-detail", args=(self.cluster_1.id,)) with self.assertNumQueries(12): - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.cluster_1.name) - self.assertEqual(response.data['hostname'], self.cluster_1.hostname) - self.assertEqual( - response.data['business_owners'][0]['username'], 'user1' - ) - self.assertEqual( - response.data['technical_owners'][0]['username'], 'user2' - ) - self.assertEqual(len(response.data['base_objects']), 2) - self.assertCountEqual(response.data['base_objects'], [ - { - 'id': self.boc_1.id, - 'url': self.get_full_url( - reverse('baseobjectcluster-detail', args=(self.boc_1.id,)) - ), - 'base_object': self.get_full_url( - reverse( - 'baseobject-detail', args=(self.boc_1.base_object.id,) - ) - ), - 'is_master': self.boc_1.is_master, - }, - { - 'id': self.boc_2.id, - 'url': self.get_full_url( - reverse('baseobjectcluster-detail', args=(self.boc_2.id,)) - ), - 'base_object': self.get_full_url(reverse( - 'baseobject-detail', args=(self.boc_2.base_object.id,) - )), - 'is_master': self.boc_2.is_master, - } - ]) - self.assertEqual( - response.data['ethernet'][0]['ipaddress']['address'], '10.20.30.40' - ) - self.assertTrue( - response.data['ethernet'][0]['ipaddress']['is_management'] - ) - self.assertEqual( - response.data['ipaddresses'], ['10.20.30.40'] - ) - self.assertEqual( - response.data['masters'][0], - self.get_full_url( - reverse('baseobject-detail', args=(self.master.id,)) - ) + self.assertEqual(response.data["name"], self.cluster_1.name) + self.assertEqual(response.data["hostname"], self.cluster_1.hostname) + self.assertEqual(response.data["business_owners"][0]["username"], "user1") + self.assertEqual(response.data["technical_owners"][0]["username"], "user2") + self.assertEqual(len(response.data["base_objects"]), 2) + self.assertCountEqual( + response.data["base_objects"], + [ + { + "id": self.boc_1.id, + "url": self.get_full_url( + reverse("baseobjectcluster-detail", args=(self.boc_1.id,)) + ), + "base_object": self.get_full_url( + reverse("baseobject-detail", args=(self.boc_1.base_object.id,)) + ), + "is_master": self.boc_1.is_master, + }, + { + "id": self.boc_2.id, + "url": self.get_full_url( + reverse("baseobjectcluster-detail", args=(self.boc_2.id,)) + ), + "base_object": self.get_full_url( + reverse("baseobject-detail", args=(self.boc_2.base_object.id,)) + ), + "is_master": self.boc_2.is_master, + }, + ], + ) + self.assertEqual( + response.data["ethernet"][0]["ipaddress"]["address"], "10.20.30.40" + ) + self.assertTrue(response.data["ethernet"][0]["ipaddress"]["is_management"]) + self.assertEqual(response.data["ipaddresses"], ["10.20.30.40"]) + self.assertEqual( + response.data["masters"][0], + self.get_full_url(reverse("baseobject-detail", args=(self.master.id,))), ) diff --git a/src/ralph/data_center/tests/test_forms.py b/src/ralph/data_center/tests/test_forms.py index 7dc083f501..9e63e80bcf 100755 --- a/src/ralph/data_center/tests/test_forms.py +++ b/src/ralph/data_center/tests/test_forms.py @@ -7,10 +7,7 @@ from ralph.assets.models import Ethernet, ObjectModelType from ralph.assets.tests.factories import DataCenterAssetModelFactory from ralph.data_center.models import DataCenterAsset -from ralph.data_center.tests.factories import ( - DataCenterAssetFactory, - RackFactory -) +from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory from ralph.networks.forms import validate_is_management from ralph.networks.models import IPAddress from ralph.networks.tests.factories import IPAddressFactory @@ -22,24 +19,20 @@ class EmptyForm: class NetworkLineFormsetTest(RalphTestCase): - def test_validate_one_management(self): form_1 = EmptyForm() form_1.cleaned_data = { - 'DELETE': False, - 'is_management': True, + "DELETE": False, + "is_management": True, } form_2 = EmptyForm() form_2.cleaned_data = { - 'DELETE': False, - 'is_management': True, + "DELETE": False, + "is_management": True, } with self.assertRaisesRegex( ValidationError, - ( - 'Only one management IP address can be assigned ' - 'to this asset' - ) + ("Only one management IP address can be assigned " "to this asset"), ): validate_is_management([form_1, form_2]) @@ -50,209 +43,233 @@ def setUp(self): self.dca1 = DataCenterAssetFactory(rack=RackFactory(), position=2) self.user = get_user_model().objects.create_superuser( - username='root', - password='password', - email='email@email.pl' + username="root", password="password", email="email@email.pl" ) - result = self.client.login(username='root', password='password') + result = self.client.login(username="root", password="password") self.assertEqual(result, True) self.factory = RequestFactory() def _get_initial_data(self, dca=None): dca = dca or self.dca data = { - 'barcode': dca.barcode, - 'depreciation_rate': 25, - 'rack': dca.rack.pk, - 'hostname': dca.hostname, - 'model': dca.model.pk, - 'orientation': 1, - 'position': dca.position, - 'service_env': dca.service_env.pk, - 'sn': dca.sn, - 'property_of': dca.property_of.id, - 'status': 1, - 'custom_fields-customfieldvalue-content_type-object_id-INITIAL_FORMS': '0', - 'custom_fields-customfieldvalue-content_type-object_id-MAX_NUM_FORMS': '1000', - 'custom_fields-customfieldvalue-content_type-object_id-MIN_NUM_FORMS': '0', - 'custom_fields-customfieldvalue-content_type-object_id-TOTAL_FORMS': '3', + "barcode": dca.barcode, + "depreciation_rate": 25, + "rack": dca.rack.pk, + "hostname": dca.hostname, + "model": dca.model.pk, + "orientation": 1, + "position": dca.position, + "service_env": dca.service_env.pk, + "sn": dca.sn, + "property_of": dca.property_of.id, + "status": 1, + "custom_fields-customfieldvalue-content_type-object_id-INITIAL_FORMS": "0", + "custom_fields-customfieldvalue-content_type-object_id-MAX_NUM_FORMS": "1000", + "custom_fields-customfieldvalue-content_type-object_id-MIN_NUM_FORMS": "0", + "custom_fields-customfieldvalue-content_type-object_id-TOTAL_FORMS": "3", } return data def test_enter_valid_mgmt_should_pass(self): data = self._get_initial_data() - data.update({ - 'management_ip': '10.20.30.40', - 'management_hostname': 'qwerty.mydc.net', - }) + data.update( + { + "management_ip": "10.20.30.40", + "management_hostname": "qwerty.mydc.net", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 302) self.dca.refresh_from_db() - self.assertEqual(self.dca.management_ip, '10.20.30.40') - self.assertEqual(self.dca.management_hostname, 'qwerty.mydc.net') + self.assertEqual(self.dca.management_ip, "10.20.30.40") + self.assertEqual(self.dca.management_hostname, "qwerty.mydc.net") def test_enter_duplicated_mgmt_ip_should_not_pass(self): IPAddressFactory( - is_management=True, address='10.20.30.41', + is_management=True, + address="10.20.30.41", ethernet__base_object=self.dca1, ) data = self._get_initial_data() - data.update({ - 'management_ip': '10.20.30.41', - 'management_hostname': 'qwerty.mydc.net', - }) + data.update( + { + "management_ip": "10.20.30.41", + "management_hostname": "qwerty.mydc.net", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 200) self.dca.refresh_from_db() self.assertIn( - 'Management IP is already assigned to', - response.context['errors'][0][0] + "Management IP is already assigned to", response.context["errors"][0][0] ) def test_enter_duplicated_mgmt_hostname_should_not_pass(self): IPAddressFactory( - is_management=True, address='10.20.30.41', - hostname='qwerty.mydc.net', + is_management=True, + address="10.20.30.41", + hostname="qwerty.mydc.net", ethernet__base_object=self.dca1, ) data = self._get_initial_data() - data.update({ - 'management_ip': '10.20.30.42', - 'management_hostname': 'qwerty.mydc.net', - }) + data.update( + { + "management_ip": "10.20.30.42", + "management_hostname": "qwerty.mydc.net", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 200) self.assertIn( - 'Management hostname is already assigned to', - response.context['errors'][0][0] + "Management hostname is already assigned to", + response.context["errors"][0][0], ) def test_reenter_mgmt_ip_should_pass(self): IPAddressFactory( - is_management=True, address='10.20.30.41', + is_management=True, + address="10.20.30.41", ethernet__base_object=self.dca, # mgmt ip assigned to the same obj ) data = self._get_initial_data() - data.update({ - 'management_ip': '10.20.30.41', - 'management_hostname': 'qwerty.mydc.net', - }) + data.update( + { + "management_ip": "10.20.30.41", + "management_hostname": "qwerty.mydc.net", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 302) self.dca.refresh_from_db() - self.assertEqual(self.dca.management_ip, '10.20.30.41') - self.assertEqual(self.dca.management_hostname, 'qwerty.mydc.net') + self.assertEqual(self.dca.management_ip, "10.20.30.41") + self.assertEqual(self.dca.management_hostname, "qwerty.mydc.net") def test_change_mgmt_ip_should_pass(self): IPAddressFactory( - is_management=True, address='10.20.30.41', + is_management=True, + address="10.20.30.41", ethernet__base_object=self.dca, ) ip_count = IPAddress.objects.count() data = self._get_initial_data() - data.update({ - 'management_ip': '10.20.30.42', - 'management_hostname': 'qwerty22.mydc.net', - }) + data.update( + { + "management_ip": "10.20.30.42", + "management_hostname": "qwerty22.mydc.net", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 302) self.dca.refresh_from_db() - self.assertEqual(self.dca.management_ip, '10.20.30.42') - self.assertEqual(self.dca.management_hostname, 'qwerty22.mydc.net') + self.assertEqual(self.dca.management_ip, "10.20.30.42") + self.assertEqual(self.dca.management_hostname, "qwerty22.mydc.net") self.assertEqual(ip_count, IPAddress.objects.count()) def test_clean_mgmt_hostname_should_pass(self): IPAddressFactory( - is_management=True, address='10.20.30.41', + is_management=True, + address="10.20.30.41", ethernet__base_object=self.dca, ) data = self._get_initial_data() - data.update({ - 'management_ip': '10.20.30.42', - 'management_hostname': '', - }) + data.update( + { + "management_ip": "10.20.30.42", + "management_hostname": "", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 302) self.dca.refresh_from_db() - self.assertEqual(self.dca.management_ip, '10.20.30.42') - self.assertEqual(self.dca.management_hostname, '') + self.assertEqual(self.dca.management_ip, "10.20.30.42") + self.assertEqual(self.dca.management_hostname, "") def test_clean_mgmt_ip_when_mgmt_hostname_is_not_empty_should_not_pass(self): # noqa IPAddressFactory( - is_management=True, address='10.20.30.41', + is_management=True, + address="10.20.30.41", ethernet__base_object=self.dca, ) data = self._get_initial_data() - data.update({ - 'management_ip': '', - 'management_hostname': 'qwerty.mydc.net', - }) + data.update( + { + "management_ip": "", + "management_hostname": "qwerty.mydc.net", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 200) self.assertIn( - 'Management IP could not be empty when management hostname is passed', # noqa - response.context['errors'][0][0] + "Management IP could not be empty when management hostname is passed", # noqa + response.context["errors"][0][0], ) def test_delete_mgmt(self): ip = IPAddressFactory( - is_management=True, address='10.20.30.41', - hostname='qwerty.mydc.net', + is_management=True, + address="10.20.30.41", + hostname="qwerty.mydc.net", ethernet__base_object=self.dca, ) eth = ip.ethernet ip_count = IPAddress.objects.count() data = self._get_initial_data() - data.update({ - 'management_ip': '', - 'management_hostname': '', - }) + data.update( + { + "management_ip": "", + "management_hostname": "", + } + ) response = self.client.post(self.dca.get_absolute_url(), data) self.assertEqual(response.status_code, 302) self.dca.refresh_from_db() - self.assertEqual(self.dca.management_ip, '') - self.assertEqual(self.dca.management_hostname, '') + self.assertEqual(self.dca.management_ip, "") + self.assertEqual(self.dca.management_hostname, "") self.assertEqual(IPAddress.objects.count(), ip_count - 1) self.assertEqual(len(IPAddress.objects.filter(pk=ip.pk)), 0) self.assertEqual(len(Ethernet.objects.filter(pk=eth.pk)), 0) def test_create_new_data_center_asset_with_management(self): data = self._get_initial_data() - data.update({ - 'barcode': '1234', - 'sn': '321', - 'management_ip': '10.20.30.44', - 'management_hostname': 'qwerty.mydc.net', - }) + data.update( + { + "barcode": "1234", + "sn": "321", + "management_ip": "10.20.30.44", + "management_hostname": "qwerty.mydc.net", + } + ) response = self.client.post( - reverse('admin:data_center_datacenterasset_add'), data + reverse("admin:data_center_datacenterasset_add"), data ) self.assertEqual(response.status_code, 302) - dca = DataCenterAsset.objects.get(barcode='1234') - self.assertEqual(dca.management_ip, '10.20.30.44') - self.assertEqual(dca.management_hostname, 'qwerty.mydc.net') + dca = DataCenterAsset.objects.get(barcode="1234") + self.assertEqual(dca.management_ip, "10.20.30.44") + self.assertEqual(dca.management_hostname, "qwerty.mydc.net") def test_create_new_data_center_asset_without_management(self): data = self._get_initial_data() - data.update({ - 'barcode': '1234', - 'sn': '321', - 'management_ip': '', - 'management_hostname': '', - }) + data.update( + { + "barcode": "1234", + "sn": "321", + "management_ip": "", + "management_hostname": "", + } + ) ip_count = IPAddress.objects.count() response = self.client.post( - reverse('admin:data_center_datacenterasset_add'), data + reverse("admin:data_center_datacenterasset_add"), data ) self.assertEqual(response.status_code, 302) - dca = DataCenterAsset.objects.get(barcode='1234') - self.assertEqual(dca.management_ip, '') - self.assertEqual(dca.management_hostname, '') + dca = DataCenterAsset.objects.get(barcode="1234") + self.assertEqual(dca.management_ip, "") + self.assertEqual(dca.management_hostname, "") self.assertEqual(IPAddress.objects.count(), ip_count) def test_get_add_form(self): response = self.client.get( - reverse('admin:data_center_datacenterasset_add'), + reverse("admin:data_center_datacenterasset_add"), ) self.assertEqual(response.status_code, 200) @@ -261,41 +278,30 @@ def test_get_add_details_form(self): self.assertEqual(response.status_code, 200) def test_get_add_details_form_with_management_ip(self): - self.dca.management_ip = '10.20.30.40' - self.dca.management_hostname = 'qwerty.mydc.net' + self.dca.management_ip = "10.20.30.40" + self.dca.management_hostname = "qwerty.mydc.net" response = self.client.get(self.dca.get_absolute_url()) self.assertEqual(response.status_code, 200) def test_model_asset_type_data_center_shall_pass(self): data_center_model = DataCenterAssetModelFactory( - type=ObjectModelType.from_name('data_center') + type=ObjectModelType.from_name("data_center") ) data = self._get_initial_data() - data.update({ - 'model': data_center_model.pk - }) - response = self.client.post( - self.dca.get_absolute_url(), data - ) + data.update({"model": data_center_model.pk}) + response = self.client.post(self.dca.get_absolute_url(), data) self.dca.refresh_from_db() self.assertEqual(response.status_code, 302) self.assertEqual(self.dca.model, data_center_model) def test_model_asset_type_back_office_asset_shall_not_pass(self): back_office_model = DataCenterAssetModelFactory( - type=ObjectModelType.from_name('back_office') + type=ObjectModelType.from_name("back_office") ) data = self._get_initial_data() - data.update({ - 'model': back_office_model.pk - }) - response = self.client.post( - self.dca.get_absolute_url(), data - ) + data.update({"model": back_office_model.pk}) + response = self.client.post(self.dca.get_absolute_url(), data) self.dca.refresh_from_db() - self.assertIn( - 'Model must be of', - response.content.decode('utf-8') - ) + self.assertIn("Model must be of", response.content.decode("utf-8")) self.assertNotEqual(self.dca.model, back_office_model) self.assertEqual(response.status_code, 200) diff --git a/src/ralph/data_center/tests/test_models.py b/src/ralph/data_center/tests/test_models.py index 6ec08c996e..244c308ba2 100644 --- a/src/ralph/data_center/tests/test_models.py +++ b/src/ralph/data_center/tests/test_models.py @@ -10,7 +10,7 @@ from ralph.data_center.models.choices import DataCenterAssetStatus, Orientation from ralph.data_center.models.physical import ( assign_additional_hostname_choices, - DataCenterAsset + DataCenterAsset, ) from ralph.data_center.models.virtual import BaseObjectCluster from ralph.data_center.tests.factories import ( @@ -18,14 +18,14 @@ ClusterTypeFactory, DataCenterAssetFactory, DataCenterAssetModelFactory, - RackFactory + RackFactory, ) from ralph.lib.transitions.models import Transition, TransitionModel from ralph.networks.models import IPAddress from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory + NetworkFactory, ) from ralph.tests import RalphTestCase @@ -44,8 +44,8 @@ def setUp(self): def test_convert_to_backoffice_asset(self): dc_asset = DataCenterAssetFactory() transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(dc_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(dc_asset, "status"), source=0, target=0, ) @@ -56,39 +56,33 @@ def test_convert_to_backoffice_asset(self): region=RegionFactory().id, warehouse=WarehouseFactory().id, request=None, - transition_id=transition.pk + transition_id=transition.pk, ) bo_asset = BackOfficeAsset.objects.get(pk=dc_asset_pk) - self.assertFalse( - DataCenterAsset.objects.filter(pk=dc_asset_pk).exists() - ) + self.assertFalse(DataCenterAsset.objects.filter(pk=dc_asset_pk).exists()) self.assertEqual(bo_asset.hostname, hostname) def test_convert_to_backoffice_asset_preserves_status_name(self): dc_asset = DataCenterAssetFactory( - status=DataCenterAssetStatus.from_name('damaged') + status=DataCenterAssetStatus.from_name("damaged") ) transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(dc_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(dc_asset, "status"), source=0, target=0, ) dc_asset_pk = dc_asset.pk - dc_asset_status_name = DataCenterAssetStatus.from_id( - dc_asset.status - ).name + dc_asset_status_name = DataCenterAssetStatus.from_id(dc_asset.status).name DataCenterAsset.convert_to_backoffice_asset( instances=[dc_asset], region=RegionFactory().id, warehouse=WarehouseFactory().id, request=None, - transition_id=transition.pk + transition_id=transition.pk, ) bo_asset = BackOfficeAsset.objects.get(pk=dc_asset_pk) - bo_asset_status_name = BackOfficeAssetStatus.from_id( - bo_asset.status - ).name + bo_asset_status_name = BackOfficeAssetStatus.from_id(bo_asset.status).name self.assertEqual(dc_asset_status_name, bo_asset_status_name) def test_convert_to_backoffice_asset_uses_default_from_transition(self): @@ -96,29 +90,25 @@ def test_convert_to_backoffice_asset_uses_default_from_transition(self): "new" # status name common for dc_asset and bo_asset ).id dc_asset = DataCenterAssetFactory( - status=DataCenterAssetStatus.from_name('damaged') + status=DataCenterAssetStatus.from_name("damaged") ) transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(dc_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(dc_asset, "status"), source=0, target=target_status_id, ) dc_asset_pk = dc_asset.pk - target_status_name = DataCenterAssetStatus.from_id( - target_status_id - ).name + target_status_name = DataCenterAssetStatus.from_id(target_status_id).name DataCenterAsset.convert_to_backoffice_asset( instances=[dc_asset], region=RegionFactory().id, warehouse=WarehouseFactory().id, request=None, - transition_id=transition.pk + transition_id=transition.pk, ) bo_asset = BackOfficeAsset.objects.get(pk=dc_asset_pk) - bo_asset_status_name = BackOfficeAssetStatus.from_id( - bo_asset.status - ).name + bo_asset_status_name = BackOfficeAssetStatus.from_id(bo_asset.status).name self.assertEqual(target_status_name, bo_asset_status_name) def test_convert_to_backoffice_asset_uses_default_from_settings(self): @@ -126,29 +116,25 @@ def test_convert_to_backoffice_asset_uses_default_from_settings(self): settings.CONVERT_TO_BACKOFFICE_ASSET_DEFAULT_STATUS_ID ).id dc_asset = DataCenterAssetFactory( - status=DataCenterAssetStatus.from_name('pre_liquidated') + status=DataCenterAssetStatus.from_name("pre_liquidated") ) transition = Transition.objects.create( - name='transition', - model=TransitionModel.get_for_field(dc_asset, 'status'), + name="transition", + model=TransitionModel.get_for_field(dc_asset, "status"), source=0, target=0, ) dc_asset_pk = dc_asset.pk - target_status_name = DataCenterAssetStatus.from_id( - target_status_id - ).name + target_status_name = DataCenterAssetStatus.from_id(target_status_id).name DataCenterAsset.convert_to_backoffice_asset( instances=[dc_asset], region=RegionFactory().id, warehouse=WarehouseFactory().id, request=None, - transition_id=transition.pk + transition_id=transition.pk, ) bo_asset = BackOfficeAsset.objects.get(pk=dc_asset_pk) - bo_asset_status_name = BackOfficeAssetStatus.from_id( - bo_asset.status - ).name + bo_asset_status_name = BackOfficeAssetStatus.from_id(bo_asset.status).name self.assertEqual(target_status_name, bo_asset_status_name) # ========================================================================= @@ -156,51 +142,45 @@ def test_convert_to_backoffice_asset_uses_default_from_settings(self): # ========================================================================= @unpack @data( - ('1A',), - ('1B',), - ('9A',), - ('9B',), - ('10A',), - ('10B',), - ('16A',), - ('16B',), - ('1',), - ('9',), - ('10',), - ('16',), + ("1A",), + ("1B",), + ("9A",), + ("9B",), + ("10A",), + ("10B",), + ("16A",), + ("16B",), + ("1",), + ("9",), + ("10",), + ("16",), ) def test_should_pass_when_slot_no_is_correct(self, slot_no): - slot_no_field: Field = self.dc_asset._meta.get_field('slot_no') + slot_no_field: Field = self.dc_asset._meta.get_field("slot_no") slot_no_field.clean(slot_no, self.dc_asset) @unpack @data( - ('1C',), - ('0A',), - ('0',), - ('B',), - ('17A',), - ('17B',), - ('20A',), - ('1a',), - ('1b',), - ('111',), + ("1C",), + ("0A",), + ("0",), + ("B",), + ("17A",), + ("17B",), + ("20A",), + ("1a",), + ("1b",), + ("111",), ) - def test_should_raise_validation_error_when_slot_no_is_incorrect( - self, slot_no - ): - slot_no_field: Field = self.dc_asset._meta.get_field('slot_no') + def test_should_raise_validation_error_when_slot_no_is_incorrect(self, slot_no): + slot_no_field: Field = self.dc_asset._meta.get_field("slot_no") with self.assertRaises(ValidationError): slot_no_field.clean(slot_no, self.dc_asset) def test_should_raise_validation_error_when_slot_no_is_busy(self): model = DataCenterAssetModelFactory(has_parent=True) - DataCenterAssetFactory( - parent=self.dc_asset, slot_no=1, model=model - ) - dc_asset = DataCenterAssetFactory( - parent=self.dc_asset, model=model - ) + DataCenterAssetFactory(parent=self.dc_asset, slot_no=1, model=model) + dc_asset = DataCenterAssetFactory(parent=self.dc_asset, model=model) dc_asset.slot_no = 1 with self.assertRaises(ValidationError): dc_asset.clean() @@ -208,35 +188,35 @@ def test_should_raise_validation_error_when_slot_no_is_busy(self): def test_should_pass_when_slot_no_is_busy_but_different_orientation(self): model = DataCenterAssetModelFactory(has_parent=True) DataCenterAssetFactory( - parent=self.dc_asset, slot_no=1, model=model, + parent=self.dc_asset, + slot_no=1, + model=model, orientation=Orientation.back, ) - dc_asset = DataCenterAssetFactory( - parent=self.dc_asset, model=model - ) + dc_asset = DataCenterAssetFactory(parent=self.dc_asset, model=model) dc_asset.slot_no = 1 dc_asset._validate_slot_no() def test_should_raise_validation_error_when_empty_slot_no_on_blade(self): dc_asset = DataCenterAssetFactory(model__has_parent=True) - dc_asset.slot_no = '' + dc_asset.slot_no = "" with self.assertRaises(ValidationError): dc_asset._validate_slot_no() def test_should_raise_validation_error_when_slot_not_filled_when_not_blade(self): # noqa dc_asset = DataCenterAssetFactory(model__has_parent=False) - dc_asset.slot_no = '1A' + dc_asset.slot_no = "1A" with self.assertRaises(ValidationError): dc_asset._validate_slot_no() def test_should_pass_when_slot_no_filled_on_blade(self): dc_asset = DataCenterAssetFactory(model__has_parent=True) - dc_asset.slot_no = '1A' + dc_asset.slot_no = "1A" dc_asset._validate_slot_no() def test_should_pass_when_slot_not_filled_without_model(self): dc_asset = DataCenterAsset() - dc_asset.slot_no = '1A' + dc_asset.slot_no = "1A" dc_asset._validate_slot_no() # ========================================================================= @@ -252,9 +232,7 @@ def test_should_pass_when_slot_not_filled_without_model(self): (10, Orientation.back), (100, Orientation.middle), ) - def test_should_pass_when_orientation_is_correct( - self, position, orientation - ): + def test_should_pass_when_orientation_is_correct(self, position, orientation): self.dc_asset.position = position self.dc_asset.orientation = orientation self.dc_asset._validate_orientation() @@ -297,11 +275,7 @@ def test_should_pass_when_rack_is_null(self): self.dc_asset._validate_position_in_rack() @unpack - @data( - (10, 9), - (1, 0), - (-1, 10) - ) + @data((10, 9), (1, 0), (-1, 10)) def test_should_raise_validation_error_when_position_in_rack_is_incorrect( self, position, rack_max_height ): @@ -328,7 +302,9 @@ def test_should_pass_when_position_is_not_passed_and_rack_doesnt_require_it(self self.dc_asset.rack = RackFactory(require_position=False) self.dc_asset._validate_position() - def test_should_raise_validation_error_when_position_is_not_passed_and_rack_requires_it(self): # noqa + def test_should_raise_validation_error_when_position_is_not_passed_and_rack_requires_it( + self, + ): # noqa self.dc_asset.position = None self.dc_asset.rack = RackFactory(require_position=True) with self.assertRaises(ValidationError): @@ -337,8 +313,7 @@ def test_should_raise_validation_error_when_position_is_not_passed_and_rack_requ def test_update_rack_when_parent_rack_is_change(self): rack_1, rack_2 = RackFactory.create_batch(2) parent_asset = DataCenterAssetFactory( - rack=rack_1, - model=DataCenterAssetModelFactory(has_parent=True) + rack=rack_1, model=DataCenterAssetModelFactory(has_parent=True) ) dc_asset = DataCenterAssetFactory(parent=parent_asset) parent_asset.rack = rack_2 @@ -349,9 +324,7 @@ def test_update_rack_when_parent_rack_is_change(self): def test_update_position_when_parent_position_is_change(self): rack = RackFactory() parent_asset = DataCenterAssetFactory( - rack=rack, - position=1, - model=DataCenterAssetModelFactory(has_parent=True) + rack=rack, position=1, model=DataCenterAssetModelFactory(has_parent=True) ) dc_asset = DataCenterAssetFactory(parent=parent_asset, position=2) parent_asset.position = 4 @@ -365,12 +338,12 @@ def test_update_position_when_parent_position_is_change(self): def _prepare_rack(self, dc_asset, address, network_address, rack=None): self.rack = rack or RackFactory() self.net_env = NetworkEnvironmentFactory( - hostname_template_prefix='server_1', - hostname_template_postfix='.mydc.net', + hostname_template_prefix="server_1", + hostname_template_postfix=".mydc.net", ) self.net_env2 = NetworkEnvironmentFactory( - hostname_template_prefix='server_2', - hostname_template_postfix='.mydc.net', + hostname_template_prefix="server_2", + hostname_template_postfix=".mydc.net", ) self.net = NetworkFactory( network_environment=self.net_env, @@ -378,83 +351,74 @@ def _prepare_rack(self, dc_asset, address, network_address, rack=None): ) self.net2 = NetworkFactory( network_environment=self.net_env2, - address='10.20.30.0/24', + address="10.20.30.0/24", ) self.net.racks.add(self.rack) self.net2.racks.add(self.rack) dc_asset.rack = self.rack dc_asset.save() - IPAddressFactory( - ethernet__base_object=self.dc_asset, address=address - ) + IPAddressFactory(ethernet__base_object=self.dc_asset, address=address) def test_network_environment(self): - self._prepare_rack(self.dc_asset, '192.168.1.11', '192.168.1.0/24') + self._prepare_rack(self.dc_asset, "192.168.1.11", "192.168.1.0/24") self.assertEqual(self.dc_asset.network_environment, self.net_env) def test_network_environment_null(self): - self._prepare_rack(self.dc_asset, '192.168.1.11', '192.222.1.0/24') + self._prepare_rack(self.dc_asset, "192.168.1.11", "192.222.1.0/24") self.assertIsNone(self.dc_asset.network_environment) # ========================================================================= # next free hostname # ========================================================================= def test_get_next_free_hostname(self): - self._prepare_rack(self.dc_asset, '192.168.1.11', '192.168.1.0/24') + self._prepare_rack(self.dc_asset, "192.168.1.11", "192.168.1.0/24") self.assertEqual( - self.dc_asset.get_next_free_hostname(), - 'server_10001.mydc.net' + self.dc_asset.get_next_free_hostname(), "server_10001.mydc.net" ) # running it again shouldn't change next hostname self.assertEqual( - self.dc_asset.get_next_free_hostname(), - 'server_10001.mydc.net' + self.dc_asset.get_next_free_hostname(), "server_10001.mydc.net" ) def test_get_next_free_hostname_without_network_env(self): - self.assertEqual(self.dc_asset.get_next_free_hostname(), '') + self.assertEqual(self.dc_asset.get_next_free_hostname(), "") def test_issue_next_free_hostname(self): - self._prepare_rack(self.dc_asset, '192.168.1.11', '192.168.1.0/24') + self._prepare_rack(self.dc_asset, "192.168.1.11", "192.168.1.0/24") self.assertEqual( - self.dc_asset.issue_next_free_hostname(), - 'server_10001.mydc.net' + self.dc_asset.issue_next_free_hostname(), "server_10001.mydc.net" ) # running it again should change next hostname self.assertEqual( - self.dc_asset.issue_next_free_hostname(), - 'server_10002.mydc.net' + self.dc_asset.issue_next_free_hostname(), "server_10002.mydc.net" ) def test_issue_next_free_hostname_without_network_env(self): - self.assertEqual(self.dc_asset.issue_next_free_hostname(), '') + self.assertEqual(self.dc_asset.issue_next_free_hostname(), "") # ========================================================================= # available networks # ========================================================================= def test_get_available_networks(self): - self._prepare_rack(self.dc_asset, '192.168.1.1', '192.168.1.0/24') - self.net3 = NetworkFactory(address='192.168.3.0/24') + self._prepare_rack(self.dc_asset, "192.168.1.1", "192.168.1.0/24") + self.net3 = NetworkFactory(address="192.168.3.0/24") self.assertCountEqual( - self.dc_asset._get_available_networks(), - [self.net, self.net2] + self.dc_asset._get_available_networks(), [self.net, self.net2] ) def test_get_available_networks_is_broadcasted_in_dhcp(self): - self._prepare_rack(self.dc_asset, '192.168.1.1', '192.168.1.0/24') - self.net3 = NetworkFactory( - address='192.168.3.0/24', dhcp_broadcast=True - ) + self._prepare_rack(self.dc_asset, "192.168.1.1", "192.168.1.0/24") + self.net3 = NetworkFactory(address="192.168.3.0/24", dhcp_broadcast=True) self.assertCountEqual( self.dc_asset._get_available_networks(is_broadcasted_in_dhcp=True), - [self.net, self.net2] + [self.net, self.net2], ) def test_get_available_networks_no_rack(self): - NetworkFactory(address='192.168.1.0/24') - NetworkFactory(address='192.168.2.0/24') + NetworkFactory(address="192.168.1.0/24") + NetworkFactory(address="192.168.2.0/24") self.assertEqual(self.dc_asset._get_available_networks(), []) # ========================================================================= @@ -475,73 +439,67 @@ def test_get_autocomplete_queryset(self): # management_ip # ========================================================================= def test_assign_new_management_ip_should_pass(self): - self.dc_asset.management_ip = '10.20.30.40' + self.dc_asset.management_ip = "10.20.30.40" self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.management_ip, '10.20.30.40') + self.assertEqual(self.dc_asset.management_ip, "10.20.30.40") def test_assign_existing_ip_assigned_to_another_obj_should_not_pass(self): - IPAddressFactory(address='10.20.30.40', is_management=True) + IPAddressFactory(address="10.20.30.40", is_management=True) with self.assertRaises(ValidationError): - self.dc_asset.management_ip = '10.20.30.40' + self.dc_asset.management_ip = "10.20.30.40" def test_assign_existing_ip_not_assigned_to_another_obj_should_pass(self): - IPAddressFactory(address='10.20.30.40', ethernet=None) - self.dc_asset.management_ip = '10.20.30.40' + IPAddressFactory(address="10.20.30.40", ethernet=None) + self.dc_asset.management_ip = "10.20.30.40" self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.management_ip, '10.20.30.40') + self.assertEqual(self.dc_asset.management_ip, "10.20.30.40") def test_change_mgmt_ip_for_new_ip_should_pass(self): - self.dc_asset.management_ip = '10.20.30.40' + self.dc_asset.management_ip = "10.20.30.40" self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.management_ip, '10.20.30.40') - self.dc_asset.management_ip = '10.20.30.41' + self.assertEqual(self.dc_asset.management_ip, "10.20.30.40") + self.dc_asset.management_ip = "10.20.30.41" self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.management_ip, '10.20.30.41') - self.assertFalse( - IPAddress.objects.filter(address='10.20.30.40').exists() - ) + self.assertEqual(self.dc_asset.management_ip, "10.20.30.41") + self.assertFalse(IPAddress.objects.filter(address="10.20.30.40").exists()) def test_change_mgmt_ip_for_existing_ip_without_object_should_pass(self): - IPAddressFactory(address='10.20.30.42', ethernet=None) - self.dc_asset.management_ip = '10.20.30.40' + IPAddressFactory(address="10.20.30.42", ethernet=None) + self.dc_asset.management_ip = "10.20.30.40" self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.management_ip, '10.20.30.40') - self.dc_asset.management_ip = '10.20.30.42' + self.assertEqual(self.dc_asset.management_ip, "10.20.30.40") + self.dc_asset.management_ip = "10.20.30.42" self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.management_ip, '10.20.30.42') - self.assertFalse( - IPAddress.objects.filter(address='10.20.30.40').exists() - ) + self.assertEqual(self.dc_asset.management_ip, "10.20.30.42") + self.assertFalse(IPAddress.objects.filter(address="10.20.30.40").exists()) def test_change_mgmt_ip_for_existing_ip_with_object_should_not_pass(self): - IPAddressFactory(address='10.20.30.42') - self.dc_asset.management_ip = '10.20.30.40' + IPAddressFactory(address="10.20.30.42") + self.dc_asset.management_ip = "10.20.30.40" self.dc_asset.refresh_from_db() - self.assertEqual(self.dc_asset.management_ip, '10.20.30.40') + self.assertEqual(self.dc_asset.management_ip, "10.20.30.40") with self.assertRaises(ValidationError): - self.dc_asset.management_ip = '10.20.30.42' + self.dc_asset.management_ip = "10.20.30.42" def test_should_return_only_common_networks(self): rack100 = RackFactory() rack101 = RackFactory() - rack_100_net = NetworkFactory(address='10.0.100.0/24') - rack_101_net = NetworkFactory(address='10.0.101.0/24') - common_net = NetworkFactory(address='10.0.0.0/24') + rack_100_net = NetworkFactory(address="10.0.100.0/24") + rack_101_net = NetworkFactory(address="10.0.101.0/24") + common_net = NetworkFactory(address="10.0.0.0/24") rack_100_net.racks.set([rack100]) rack_101_net.racks.set([rack101]) common_net.racks.set([rack100, rack101]) self.dc_asset_2.rack = rack100 self.dc_asset_3.rack = rack101 - rack_100_result = assign_additional_hostname_choices( - None, [self.dc_asset_2] - ) + rack_100_result = assign_additional_hostname_choices(None, [self.dc_asset_2]) common_result = assign_additional_hostname_choices( None, [self.dc_asset_2, self.dc_asset_3] ) expected_rack100_result = [ (str(rack_100_net.pk), rack_100_net), - (str(common_net.pk), common_net) + (str(common_net.pk), common_net), ] expected_common_result = [(str(common_net.pk), common_net)] self.assertCountEqual(rack_100_result, expected_rack100_result) @@ -564,16 +522,14 @@ def test_get_free_u_in_empty_rack_should_return_max_u_height(self): (47, 1, 47, 46), (47, 5, 47, 46), ) - def test_get_free_u_for_one_asset( - self, position, height, max_u_height, expected - ): + def test_get_free_u_for_one_asset(self, position, height, max_u_height, expected): rack = RackFactory(max_u_height=max_u_height) asset_kwargs = { - 'rack': rack, - 'model__height_of_device': height, - 'position': position, - 'slot_no': None, - 'orientation': Orientation.front.id, + "rack": rack, + "model__height_of_device": height, + "position": position, + "slot_no": None, + "orientation": Orientation.front.id, } DataCenterAssetFactory(**asset_kwargs) self.assertEqual(rack.get_free_u(), expected) @@ -581,11 +537,11 @@ def test_get_free_u_for_one_asset( def test_get_free_u_for_none_position(self): rack = RackFactory(max_u_height=47) asset_kwargs = { - 'rack': rack, - 'model__height_of_device': 47, - 'position': None, - 'slot_no': None, - 'orientation': Orientation.front.id, + "rack": rack, + "model__height_of_device": 47, + "position": None, + "slot_no": None, + "orientation": Orientation.front.id, } DataCenterAssetFactory(**asset_kwargs) self.assertEqual(rack.get_free_u(), 47) @@ -593,17 +549,13 @@ def test_get_free_u_for_none_position(self): def test_get_free_u_should_respect_orientation(self): rack = RackFactory(max_u_height=48) asset_common_kwargs = { - 'rack': rack, - 'model__height_of_device': 1, - 'position': 35, - 'slot_no': None + "rack": rack, + "model__height_of_device": 1, + "position": 35, + "slot_no": None, } - DataCenterAssetFactory( - orientation=Orientation.front.id, **asset_common_kwargs - ) - DataCenterAssetFactory( - orientation=Orientation.back.id, **asset_common_kwargs - ) + DataCenterAssetFactory(orientation=Orientation.front.id, **asset_common_kwargs) + DataCenterAssetFactory(orientation=Orientation.back.id, **asset_common_kwargs) self.assertEqual(rack.get_free_u(), 47) @@ -616,8 +568,7 @@ def setUp(self): ) self.master = DataCenterAssetFactory() self.boc_2 = BaseObjectCluster.objects.create( - cluster=self.cluster_1, base_object=self.master, - is_master=True + cluster=self.cluster_1, base_object=self.master, is_master=True ) def test_masters(self): @@ -634,8 +585,13 @@ def test_status_ids_are_consistent(self): self.assertEqual( statuses, [ - (1, 'new'), (2, 'in use'), (3, 'free'), (4, 'damaged'), - (5, 'liquidated'), (6, 'to deploy'), (7, 'cleaned'), - (8, 'pre liquidated') - ] + (1, "new"), + (2, "in use"), + (3, "free"), + (4, "damaged"), + (5, "liquidated"), + (6, "to deploy"), + (7, "cleaned"), + (8, "pre liquidated"), + ], ) diff --git a/src/ralph/data_center/tests/test_publishers.py b/src/ralph/data_center/tests/test_publishers.py index 7263373fc1..9b0b3ee635 100644 --- a/src/ralph/data_center/tests/test_publishers.py +++ b/src/ralph/data_center/tests/test_publishers.py @@ -5,34 +5,25 @@ class PublisherTests(RalphTestCase): - def test_get_host_data_after_deleting_securityscan(self): instance = VirtualServerFactory() security_scan = SecurityScanFactory(base_object=instance) old_hostname = instance.hostname - instance.hostname = 'hostname' + instance.hostname = "hostname" instance.save() host_data = _get_host_data(instance) - self.assertEqual( - old_hostname, - host_data['_previous_state']['hostname'] - ) - self.assertEqual( - instance.hostname, - host_data['hostname'] - ) + self.assertEqual(old_hostname, host_data["_previous_state"]["hostname"]) + self.assertEqual(instance.hostname, host_data["hostname"]) self.assertEqual( security_scan.last_scan_date.strftime("%Y-%m-%dT%H:%M:%S"), - host_data['securityscan']['last_scan_date'] + host_data["securityscan"]["last_scan_date"], ) self.assertEqual( - security_scan.scan_status.name, - host_data['securityscan']['scan_status'] + security_scan.scan_status.name, host_data["securityscan"]["scan_status"] ) instance.securityscan.delete() host_data = _get_host_data(instance) - self.assertIsNone(host_data['securityscan']) - + self.assertIsNone(host_data["securityscan"]) diff --git a/src/ralph/data_center/tests/test_signals.py b/src/ralph/data_center/tests/test_signals.py index abba2d45ec..2f9a8116b0 100644 --- a/src/ralph/data_center/tests/test_signals.py +++ b/src/ralph/data_center/tests/test_signals.py @@ -4,14 +4,10 @@ from ralph.data_center.publishers import _get_host_data from ralph.data_center.tests.factories import DataCenterAssetFullFactory -from ralph.virtual.tests.factories import ( - CloudHostFullFactory, - VirtualServerFactory -) +from ralph.virtual.tests.factories import CloudHostFullFactory, VirtualServerFactory class TestPublishing(TestCase): - def setUp(self): self.cloud_host = CloudHostFullFactory() self.dc_asset = DataCenterAssetFullFactory() @@ -31,18 +27,18 @@ def test_virtual_server_is_serialized_ok(self): def test_sending_data_includes_previous_data(self): results = [] - for obj_name in ['cloud_host', 'dc_asset', 'virtual_server']: + for obj_name in ["cloud_host", "dc_asset", "virtual_server"]: data = _get_host_data(getattr(self, obj_name)) - results.append('_previous_state' in data) + results.append("_previous_state" in data) self.assertEqual(results, [True] * 3) def test_sending_data_doesnt_raise_json_error(self): - for obj_name in ['cloud_host', 'dc_asset', 'virtual_server']: + for obj_name in ["cloud_host", "dc_asset", "virtual_server"]: json.dumps(_get_host_data(self.dc_asset)) def test_sending_data_includes_only_selected_fields(self): data = _get_host_data(self.dc_asset) self.assertEqual( - list(data['_previous_state'].keys()), + list(data["_previous_state"].keys()), self.dc_asset.previous_dc_host_update_fields, ) diff --git a/src/ralph/data_center/tests/test_subscribers.py b/src/ralph/data_center/tests/test_subscribers.py index 4178ebdde1..58d7ecc558 100644 --- a/src/ralph/data_center/tests/test_subscribers.py +++ b/src/ralph/data_center/tests/test_subscribers.py @@ -10,12 +10,12 @@ handle_create_vip_event, handle_delete_vip_event, handle_update_vip_event, - validate_vip_event_data + validate_vip_event_data, ) from ralph.data_center.tests.factories import ( ClusterFactory, EthernetFactory, - VIPFactory + VIPFactory, ) from ralph.networks.models.networks import Ethernet, IPAddress from ralph.networks.tests.factories import IPAddressFactory @@ -24,10 +24,7 @@ "non_http": False, "load_balancer": "test-lb.local", "id": 111, - "service": { - "uid": "xx-123", - "name": "test service" - }, + "service": {"uid": "xx-123", "name": "test service"}, "load_balancer_type": "HAPROXY", "port": 8000, "name": "ralph-test.local_8000", @@ -35,89 +32,88 @@ "venture": None, "protocol": "TCP", "partition": "default", - "ip": "10.20.30.40" + "ip": "10.20.30.40", } -class ValidateEventDataTestCase(TestCase): +class ValidateEventDataTestCase(TestCase): def setUp(self): self.data = deepcopy(EVENT_DATA) def test_missing_name(self): - self.data['name'] = None + self.data["name"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) - self.assertIn('missing name', errors) + self.assertIn("missing name", errors) def test_invalid_ip_address(self): - self.data['ip'] = '10.20.30.40.50' + self.data["ip"] = "10.20.30.40.50" errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) self.assertIn('invalid IP address "10.20.30.40.50"', errors) - self.data['ip'] = None + self.data["ip"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) self.assertIn('invalid IP address "None"', errors) def test_invalid_port(self): - self.data['port'] = 65536 + self.data["port"] = 65536 errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) self.assertIn('invalid port "65536"', errors) - self.data['port'] = -1 + self.data["port"] = -1 errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) self.assertIn('invalid port "-1"', errors) - self.data['port'] = None + self.data["port"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) self.assertIn('invalid port "None"', errors) def test_missing_protocol(self): - self.data['protocol'] = None + self.data["protocol"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) - self.assertIn('missing protocol', errors) + self.assertIn("missing protocol", errors) def test_missing_service_uid(self): - self.data['service']['uid'] = None + self.data["service"]["uid"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) - self.assertIn('missing service UID', errors) + self.assertIn("missing service UID", errors) - self.data['service'] = None + self.data["service"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) - self.assertIn('missing service UID', errors) + self.assertIn("missing service UID", errors) def test_missing_environment(self): - self.data['environment'] = None + self.data["environment"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 1) - self.assertIn('missing environment', errors) + self.assertIn("missing environment", errors) def test_if_errors_aggregate(self): - self.data['service'] = None - self.data['environment'] = None + self.data["service"] = None + self.data["environment"] = None errors = validate_vip_event_data(self.data) self.assertEqual(len(errors), 2) - self.assertIn('missing service UID', errors) - self.assertIn('missing environment', errors) + self.assertIn("missing service UID", errors) + self.assertIn("missing environment", errors) class HandleCreateVIPEventTestCase(TestCase): - def setUp(self): self.data = deepcopy(EVENT_DATA) def test_create_when_vip_already_exists(self): vip = VIPFactory() - self.data['ip'] = vip.ip.address - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["ip"] = vip.ip.address + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name vips = VIP.objects.all() self.assertEqual(vips.count(), 1) @@ -128,38 +124,37 @@ def test_create_when_vip_already_exists(self): self.assertEqual(vips[0].modified, modified_before) def test_create_when_service_env_does_not_exist(self): - self.data['service']['uid'] = 'non-existing-uid' + self.data["service"]["uid"] = "non-existing-uid" handle_create_vip_event(self.data) self.assertEqual(VIP.objects.count(), 0) def test_create_with_valid_event_data(self): service_env = ServiceEnvironmentFactory() - self.data['service']['uid'] = service_env.service.uid - self.data['environment'] = service_env.environment.name + self.data["service"]["uid"] = service_env.service.uid + self.data["environment"] = service_env.environment.name self.assertEqual(VIP.objects.count(), 0) handle_create_vip_event(self.data) self.assertEqual(VIP.objects.count(), 1) def test_create_with_invalid_event_data(self): - self.data['service'] = None + self.data["service"] = None self.assertEqual(VIP.objects.count(), 0) handle_create_vip_event(self.data) self.assertEqual(VIP.objects.count(), 0) class HandleUpdateVIPEventTestCase(TestCase): - def setUp(self): self.data = deepcopy(EVENT_DATA) def test_update_change_service_env(self): vip = VIPFactory() - self.data['ip'] = vip.ip.address - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["ip"] = vip.ip.address + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name service_env = ServiceEnvironmentFactory() - self.data['service']['uid'] = service_env.service.uid - self.data['environment'] = service_env.environment.name + self.data["service"]["uid"] = service_env.service.uid + self.data["environment"] = service_env.environment.name vips = VIP.objects.all() self.assertEqual(vips.count(), 1) @@ -169,23 +164,23 @@ def test_update_change_service_env(self): self.assertEqual(vips[0].service_env, service_env) def test_update_change_cluster(self): - cluster_old = ClusterFactory(name='f5-1-fake-old') + cluster_old = ClusterFactory(name="f5-1-fake-old") ethernet = EthernetFactory(base_object=cluster_old) vip = VIPFactory( ip=IPAddressFactory(ethernet=ethernet), parent=cluster_old, ) - self.data['load_balancer'] = 'f5-1-fake-new' - self.data['ip'] = vip.ip.address - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["load_balancer"] = "f5-1-fake-new" + self.data["ip"] = vip.ip.address + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name self.assertEqual(VIP.objects.count(), 1) self.assertEqual(Cluster.objects.count(), 1) self.assertEqual(Ethernet.objects.count(), 1) - + handle_update_vip_event(self.data) - + vips = VIP.objects.all() self.assertEqual(vips.count(), 1) self.assertEqual(Cluster.objects.count(), 2) @@ -193,22 +188,21 @@ def test_update_change_cluster(self): self.assertEqual(vips[0].ip.ethernet, ethernet) self.assertEqual( Ethernet.objects.get(id=ethernet.id).base_object.last_descendant.name, - self.data['load_balancer'] + self.data["load_balancer"], ) class HandleDeleteVIPEventTestCase(TestCase): - def setUp(self): self.data = deepcopy(EVENT_DATA) def test_delete_when_ip_does_not_exist(self): vip = VIPFactory() ip = IPAddressFactory() - self.data['ip'] = ip.address + self.data["ip"] = ip.address ip.delete() - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name self.assertEqual(VIP.objects.count(), 1) handle_delete_vip_event(self.data) @@ -216,9 +210,9 @@ def test_delete_when_ip_does_not_exist(self): def test_delete_with_valid_event_data(self): vip = VIPFactory() - self.data['ip'] = vip.ip.address - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["ip"] = vip.ip.address + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name self.assertEqual(VIP.objects.count(), 1) handle_delete_vip_event(self.data) @@ -226,20 +220,20 @@ def test_delete_with_valid_event_data(self): def test_delete_with_invalid_event_data(self): vip = VIPFactory() - self.data['ip'] = vip.ip.address - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["ip"] = vip.ip.address + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name - self.data['service'] = None + self.data["service"] = None self.assertEqual(VIP.objects.count(), 1) handle_delete_vip_event(self.data) self.assertEqual(VIP.objects.count(), 1) def test_ip_with_eth_being_deleted_when_no_longer_used(self): vip = VIPFactory() - self.data['ip'] = vip.ip.address - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["ip"] = vip.ip.address + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name self.assertEqual(VIP.objects.count(), 1) self.assertEqual(IPAddress.objects.count(), 1) @@ -251,9 +245,9 @@ def test_ip_with_eth_being_deleted_when_no_longer_used(self): def test_ip_with_eth_not_being_deleted_when_still_used_by_some_vip(self): vip = VIPFactory() - self.data['ip'] = vip.ip.address - self.data['port'] = vip.port - self.data['protocol'] = VIPProtocol.from_id(vip.protocol).name + self.data["ip"] = vip.ip.address + self.data["port"] = vip.port + self.data["protocol"] = VIPProtocol.from_id(vip.protocol).name vip2 = VIPFactory() vip2.ip = vip.ip vip2.save() diff --git a/src/ralph/data_center/tests/test_view.py b/src/ralph/data_center/tests/test_view.py index a63415751a..2dac52c04c 100644 --- a/src/ralph/data_center/tests/test_view.py +++ b/src/ralph/data_center/tests/test_view.py @@ -9,21 +9,18 @@ from ralph.data_center.tests.factories import ( ClusterFactory, DataCenterAssetFactory, - DataCenterAssetFullFactory + DataCenterAssetFullFactory, ) from ralph.data_center.views import RelationsView from ralph.security.models import ScanStatus -from ralph.security.tests.factories import ( - SecurityScanFactory, - VulnerabilityFactory -) +from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory from ralph.tests.mixins import ClientMixin from ralph.virtual.models import CloudHost, VirtualServer from ralph.virtual.tests.factories import ( CloudHostFactory, CloudHostFullFactory, VirtualServerFactory, - VirtualServerFullFactory + VirtualServerFullFactory, ) @@ -41,7 +38,7 @@ def test_changelist_view(self): DataCenterAssetFullFactory.create_batch(10) with self.assertNumQueries(24): self.client.get( - reverse('admin:data_center_datacenterasset_changelist'), + reverse("admin:data_center_datacenterasset_changelist"), ) @@ -56,104 +53,98 @@ def test_changelist_view(self): ClusterFactory.create_batch(4) with self.assertNumQueries(21): result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) # DCAssets - 5 # VirtualServer + hypervisors - 10 # Cluster - 4 # CloudHost + hypervisors - 8 - self.assertEqual(result.context_data['cl'].result_count, 27) + self.assertEqual(result.context_data["cl"].result_count, 27) def test_changelist_datacenterasset_location(self): DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) - self.assertContains(result, 'DC1 / SR1 / Rack #1') + self.assertContains(result, "DC1 / SR1 / Rack #1") def test_changelist_virtualserver_location(self): VirtualServerFullFactory( parent=DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', - hostname='s12345.mydc.net', + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", + hostname="s12345.mydc.net", ) ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) - self.assertContains(result, 'DC1 / SR1 / Rack #1 / s12345.mydc.net') + self.assertContains(result, "DC1 / SR1 / Rack #1 / s12345.mydc.net") def test_changelist_cloudhost_location(self): CloudHostFullFactory( hypervisor=DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', - hostname='s12345.mydc.net', + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", + hostname="s12345.mydc.net", ) ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) - self.assertContains(result, 'DC1 / SR1 / Rack #1 / s12345.mydc.net') + self.assertContains(result, "DC1 / SR1 / Rack #1 / s12345.mydc.net") def test_changelist_cluster_location(self): cluster = ClusterFactory() cluster.baseobjectcluster_set.create( is_master=True, base_object=DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', - ) + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", + ), ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) - self.assertContains(result, 'DC1 / SR1 / Rack #1') + self.assertContains(result, "DC1 / SR1 / Rack #1") class DCHostScanStatusInListingTest(ClientMixin, TestCase): - def setUp(self): self.login_as_user() self.asset = DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", securityscan=None, ) - def test_listing_show_ok_when_scan_succeed_and_no_vulnerabilities( - self - ): + def test_listing_show_ok_when_scan_succeed_and_no_vulnerabilities(self): SecurityScanFactory( - base_object=self.asset.baseobject_ptr, vulnerabilities=[], + base_object=self.asset.baseobject_ptr, + vulnerabilities=[], ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) self.assertContains(result, "Host clean") - def test_listing_show_ok_when_scan_succeed_and_vulnerability_before_deadline( - self - ): + def test_listing_show_ok_when_scan_succeed_and_vulnerability_before_deadline(self): SecurityScanFactory( base_object=self.asset.baseobject_ptr, - vulnerabilities=[ - VulnerabilityFactory(patch_deadline=tomorrow()) - ], + vulnerabilities=[VulnerabilityFactory(patch_deadline=tomorrow())], ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) self.assertContains(result, "Host clean") @@ -161,14 +152,12 @@ def test_listing_show_ok_when_scan_succeed_and_vulnerability_before_deadline( def test_listing_show_fail_when_scan_succeed_and_got_exceeded_vulnerability(self): scan = SecurityScanFactory( base_object=self.asset.baseobject_ptr, - vulnerabilities=[ - VulnerabilityFactory(patch_deadline=yesterday()) - ], + vulnerabilities=[VulnerabilityFactory(patch_deadline=yesterday())], ) self.assertTrue(scan.vulnerabilities.exists()) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) self.assertContains(result, "Vulnerable") @@ -184,7 +173,7 @@ def test_listing_show_correct_vuls_count_when_scan_has_different_vuls(self): self.assertTrue(scan.vulnerabilities.exists()) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) self.assertContains(result, "Vulnerable") @@ -196,7 +185,7 @@ def test_listing_show_failed_when_scan_failed(self): ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) self.assertContains(result, "Scan failed") @@ -208,7 +197,7 @@ def test_listing_show_failed_icon_when_scan_error(self): ) result = self.client.get( - reverse('admin:data_center_dchost_changelist'), + reverse("admin:data_center_dchost_changelist"), ) self.assertContains(result, "Scan failed") @@ -217,13 +206,14 @@ class DCHostFilterByPatchDeadline(ClientMixin, TestCase): def setUp(self): self.login_as_user() self.asset_no_vuls = DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", securityscan=None, ) self.scan_no_vuls = SecurityScanFactory( - base_object=self.asset_no_vuls.baseobject_ptr, vulnerabilities=[], + base_object=self.asset_no_vuls.baseobject_ptr, + vulnerabilities=[], ) self.today = datetime.now() @@ -231,9 +221,9 @@ def setUp(self): self.tomorrow = self.today + timedelta(days=1) self.asset_with_today_vul = DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", securityscan=None, ) self.scan_with_vuls2 = SecurityScanFactory( @@ -242,39 +232,45 @@ def setUp(self): VulnerabilityFactory( patch_deadline=self.today, ) - ] + ], ) self.asset_vuls2 = DataCenterAssetFullFactory( - rack__name='Rack #1', - rack__server_room__name='SR1', - rack__server_room__data_center__name='DC1', + rack__name="Rack #1", + rack__server_room__name="SR1", + rack__server_room__data_center__name="DC1", securityscan=None, ) self.scan_with_vuls2 = SecurityScanFactory( base_object=self.asset_vuls2.baseobject_ptr, vulnerabilities=[ - VulnerabilityFactory( - patch_deadline=self.today + timedelta(days=30) - ) - ] + VulnerabilityFactory(patch_deadline=self.today + timedelta(days=30)) + ], ) def test_patch_deadline_filters_hosts(self): - FORMAT = '%Y-%m-%d' - url = ( - '?'.join([ - reverse('admin:data_center_dchost_changelist',), - urlencode({ - 'securityscan__vulnerabilities__patch_deadline__start': self.yesterday.strftime(FORMAT), # noqa - 'securityscan__vulnerabilities__patch_deadline__end': self.tomorrow.strftime(FORMAT), # noqa - }) - ]) + FORMAT = "%Y-%m-%d" + url = "?".join( + [ + reverse( + "admin:data_center_dchost_changelist", + ), + urlencode( + { + "securityscan__vulnerabilities__patch_deadline__start": self.yesterday.strftime( + FORMAT + ), # noqa + "securityscan__vulnerabilities__patch_deadline__end": self.tomorrow.strftime( + FORMAT + ), # noqa + } + ), + ] ) response = self.client.get(url, follow=True) self.assertEqual( - int(response.context_data['cl'].result_list[0].id), + int(response.context_data["cl"].result_list[0].id), self.asset_with_today_vul.id, ) @@ -289,11 +285,9 @@ def test_should_add_cloud_hosts_to_dictionary(self): self.view.object.cloudhost_set.add(*CloudHostFactory.create_batch(4)) related_objects = {} self.view._add_cloud_hosts(related_objects) - content_type = { - c_t.content_type for c_t in related_objects['cloud_hosts'] - } + content_type = {c_t.content_type for c_t in related_objects["cloud_hosts"]} - self.assertEqual(4, len(related_objects['cloud_hosts'])) + self.assertEqual(4, len(related_objects["cloud_hosts"])) self.assertEqual(1, len(content_type)) self.assertEqual(cloud_host, content_type.pop()) @@ -302,11 +296,9 @@ def test_should_add_virtual_hosts_to_dictionary(self): self.view.object.children.add(*VirtualServerFactory.create_batch(4)) related_objects = {} self.view._add_virtual_hosts(related_objects) - content_type = { - c_t.content_type for c_t in related_objects['virtual_hosts'] - } + content_type = {c_t.content_type for c_t in related_objects["virtual_hosts"]} - self.assertEqual(4, len(related_objects['virtual_hosts'])) + self.assertEqual(4, len(related_objects["virtual_hosts"])) self.assertEqual(1, len(content_type)) self.assertEqual(virtual_server, content_type.pop()) @@ -315,23 +307,20 @@ def test_should_add_physical_hosts_to_dictionary(self): self.view.object.children.add(*DataCenterAssetFactory.create_batch(4)) related_objects = {} self.view._add_physical_hosts(related_objects) - content_type = { - c_t.content_type for c_t in related_objects['physical_hosts'] - } + content_type = {c_t.content_type for c_t in related_objects["physical_hosts"]} - self.assertEqual(4, len(related_objects['physical_hosts'])) + self.assertEqual(4, len(related_objects["physical_hosts"])) self.assertEqual(1, len(content_type)) self.assertEqual(physical_server, content_type.pop()) def test_should_add_clusters_to_dictionary(self): cluster = ContentType.objects.get_for_model(Cluster) self.view.object.clusters.add( - BaseObjectCluster(cluster=ClusterFactory()), - bulk=False + BaseObjectCluster(cluster=ClusterFactory()), bulk=False ) related_objects = {} self.view._add_clusters(related_objects) - content_type = related_objects['clusters'][0].content_type + content_type = related_objects["clusters"][0].content_type - self.assertEqual(1, len(related_objects['clusters'])) + self.assertEqual(1, len(related_objects["clusters"])) self.assertEqual(cluster, content_type) diff --git a/src/ralph/data_center/views.py b/src/ralph/data_center/views.py index b9e2aa3984..3f8c50fe40 100644 --- a/src/ralph/data_center/views.py +++ b/src/ralph/data_center/views.py @@ -6,42 +6,39 @@ class RelationsView(RalphDetailView): - icon = 'shekel' - label = 'Relations' - name = 'relations' - url_name = 'relations' - template_name = 'data_center/datacenterasset/relations.html' + icon = "shekel" + label = "Relations" + name = "relations" + url_name = "relations" + template_name = "data_center/datacenterasset/relations.html" def _add_cloud_hosts(self, related_objects): cloud_hosts = list(self.object.cloudhost_set.all()) if cloud_hosts: - related_objects['cloud_hosts'] = cloud_hosts + related_objects["cloud_hosts"] = cloud_hosts def _add_virtual_hosts(self, related_objects): virtual_server = ContentType.objects.get_for_model(VirtualServer) - virtual_hosts = list( - self.object.children.filter(content_type=virtual_server) - ) + virtual_hosts = list(self.object.children.filter(content_type=virtual_server)) if virtual_hosts: - related_objects['virtual_hosts'] = virtual_hosts + related_objects["virtual_hosts"] = virtual_hosts def _add_physical_hosts(self, related_objects): physical_server = ContentType.objects.get_for_model(DataCenterAsset) - physical_hosts = list( - self.object.children.filter(content_type=physical_server) - ) + physical_hosts = list(self.object.children.filter(content_type=physical_server)) if physical_hosts: - related_objects['physical_hosts'] = physical_hosts + related_objects["physical_hosts"] = physical_hosts def _add_clusters(self, related_objects): - clusters = [base_object.cluster - for base_object in list(self.object.clusters.all())] + clusters = [ + base_object.cluster for base_object in list(self.object.clusters.all()) + ] if clusters: - related_objects['clusters'] = clusters + related_objects["clusters"] = clusters def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -51,6 +48,6 @@ def get_context_data(self, **kwargs): self._add_virtual_hosts(related_objects) self._add_physical_hosts(related_objects) self._add_clusters(related_objects) - context['related_objects'] = related_objects + context["related_objects"] = related_objects return context diff --git a/src/ralph/data_importer/fields.py b/src/ralph/data_importer/fields.py index 9e010aa3f4..93702ddf49 100644 --- a/src/ralph/data_importer/fields.py +++ b/src/ralph/data_importer/fields.py @@ -9,11 +9,15 @@ class ThroughField(fields.Field): - def __init__( - self, through_model, through_from_field_name, through_to_field_name, - attribute=None, column_name=None, widget=None, - readonly=False + self, + through_model, + through_from_field_name, + through_to_field_name, + attribute=None, + column_name=None, + widget=None, + readonly=False, ): """ Field for through django model import/export @@ -49,49 +53,50 @@ def save(self, obj, data, is_m2m=False): value = data.get(self.column_name) current = set(self.widget.clean(value)) # filter old assignments to obj by through_model - old_objs = set([ - getattr(i, self.through_to_field_name) for i in - self.through_model.objects.filter( - **{self.through_from_field_name: obj} - ).select_related( - self.through_to_field_name - ) - ]) + old_objs = set( + [ + getattr(i, self.through_to_field_name) + for i in self.through_model.objects.filter( + **{self.through_from_field_name: obj} + ).select_related(self.through_to_field_name) + ] + ) to_add = current - old_objs to_remove = old_objs - current to_add_list = [] for i in to_add: - logger.info('Adding %s to %s/%s assignments', - i.pk, self.through_model, obj.pk - ) - to_add_list.append(self.through_model( - **{ - self.through_from_field_name: obj, - self.through_to_field_name: i - } - )) + logger.info( + "Adding %s to %s/%s assignments", i.pk, self.through_model, obj.pk + ) + to_add_list.append( + self.through_model( + **{ + self.through_from_field_name: obj, + self.through_to_field_name: i, + } + ) + ) if to_add_list: self.through_model.objects.bulk_create(to_add_list) if to_remove: logger.warning( - 'Removing assignments from %s/%s: %s', - self.through_model, obj.pk, [i.pk for i in to_remove] + "Removing assignments from %s/%s: %s", + self.through_model, + obj.pk, + [i.pk for i in to_remove], ) self.through_model.objects.filter( **{ self.through_from_field_name: obj, - '{}__in'.format(self.through_to_field_name): to_remove + "{}__in".format(self.through_to_field_name): to_remove, } ).delete() class PriceField(fields.Field): def save(self, obj, data, is_m2m=False): - price = Money( - data['price'], - data.get('price_currency', DEFAULT_CURRENCY_CODE) - ) - setattr(obj, 'price', price) + price = Money(data["price"], data.get("price_currency", DEFAULT_CURRENCY_CODE)) + setattr(obj, "price", price) diff --git a/src/ralph/data_importer/management/commands/create_network.py b/src/ralph/data_importer/management/commands/create_network.py index 9d815a4970..4fd9eb63b3 100644 --- a/src/ralph/data_importer/management/commands/create_network.py +++ b/src/ralph/data_importer/management/commands/create_network.py @@ -14,22 +14,17 @@ class Command(BaseCommand): """ def handle(self, *args, **options): - dc_name = options.get('dc_name') - create_rack = options.get('create_rack') - server_room_name = options.get('server_room_name') + dc_name = options.get("dc_name") + create_rack = options.get("create_rack") + server_room_name = options.get("server_room_name") try: - dns1_address = ipaddress.ip_address(options.get('dns1')) - dns2_address = ipaddress.ip_address(options.get('dns2')) - network_address = ipaddress.ip_address( - options.get('network_address') - ) + dns1_address = ipaddress.ip_address(options.get("dns1")) + dns2_address = ipaddress.ip_address(options.get("dns2")) + network_address = ipaddress.ip_address(options.get("network_address")) network = ipaddress.ip_network( - '{}/{}'.format( - str(network_address), - options.get('network_mask') - ) + "{}/{}".format(str(network_address), options.get("network_mask")) ) - gateway_address = ipaddress.ip_address(options.get('gateway')) + gateway_address = ipaddress.ip_address(options.get("gateway")) except ValueError as e: raise CommandError(e) @@ -45,62 +40,53 @@ def handle(self, *args, **options): def add_arguments(self, parser): parser.add_argument( - '-d', '--dc-name', - default='dc1', - dest='dc_name', - help='Data center name.' + "-d", "--dc-name", default="dc1", dest="dc_name", help="Data center name." ) parser.add_argument( - '--dns1', - default='10.0.0.11', - dest='dns1', - help='Primary DNS server.' + "--dns1", default="10.0.0.11", dest="dns1", help="Primary DNS server." ) parser.add_argument( - '--dns2', - default='10.0.0.12', - dest='dns2', - help='Secondary DNS server.' + "--dns2", default="10.0.0.12", dest="dns2", help="Secondary DNS server." ) parser.add_argument( - '--network-address', - default='10.0.0.0', - dest='network_address', - help='Network address.' + "--network-address", + default="10.0.0.0", + dest="network_address", + help="Network address.", ) parser.add_argument( - '--network-mask', - default='24', - dest='network_mask', - help='Network mask.' + "--network-mask", default="24", dest="network_mask", help="Network mask." ) parser.add_argument( - '--gateway', - default='10.0.0.1', - dest='gateway', - help='Default gateway.' + "--gateway", default="10.0.0.1", dest="gateway", help="Default gateway." ) parser.add_argument( - '--server-room-name', + "--server-room-name", default="server room", - dest='server_room_name', - help='Server room name.' + dest="server_room_name", + help="Server room name.", ) parser.add_argument( - '--create-rack', - action='store_true', - help='Create rack for which the subnet will be used.' + "--create-rack", + action="store_true", + help="Create rack for which the subnet will be used.", ) @classmethod @transaction.atomic def create_network( - cls, network, dns1_address, dns2_address, gateway_address, dc_name, - server_room_name, create_rack=False + cls, + network, + dns1_address, + dns2_address, + gateway_address, + dc_name, + server_room_name, + create_rack=False, ): data_center, _ = DataCenter.objects.get_or_create(name=dc_name) network_environment, _ = NetworkEnvironment.objects.get_or_create( - name='prod', data_center=data_center + name="prod", data_center=data_center ) server_room, _ = ServerRoom.objects.get_or_create( data_center=data_center, name=server_room_name @@ -115,13 +101,12 @@ def create_network( dns1, _ = DNSServer.objects.get_or_create(ip_address=str(dns1_address)) dns2, _ = DNSServer.objects.get_or_create(ip_address=str(dns2_address)) dns_server_group, _ = DNSServerGroup.objects.get_or_create( - name='{}-dns-group'.format(dc_name) + name="{}-dns-group".format(dc_name) ) dns_order = 10 for dns in [dns1, dns2]: DNSServerGroupOrder.objects.get_or_create( - dns_server=dns, dns_server_group=dns_server_group, - order=dns_order + dns_server=dns, dns_server_group=dns_server_group, order=dns_order ) dns_order += 10 gateway_address, _ = IPAddress.objects.get_or_create( @@ -132,7 +117,7 @@ def create_network( address=str(network), gateway=gateway_address, network_environment=network_environment, - dns_servers_group=dns_server_group + dns_servers_group=dns_server_group, ) if rack: network.racks.add(rack) diff --git a/src/ralph/data_importer/management/commands/create_preboot_configuration.py b/src/ralph/data_importer/management/commands/create_preboot_configuration.py index b311bd7e25..d2110977cd 100644 --- a/src/ralph/data_importer/management/commands/create_preboot_configuration.py +++ b/src/ralph/data_importer/management/commands/create_preboot_configuration.py @@ -1,61 +1,62 @@ from django.core.management import BaseCommand from django.db import transaction -from ralph.deployment.models import ( - Preboot, - PrebootConfiguration, - PrebootItemType -) +from ralph.deployment.models import Preboot, PrebootConfiguration, PrebootItemType class Command(BaseCommand): """ Generate a production ready preboot configuration. """ + @transaction.atomic def handle(self, *args, **options): - kickstart_file = options.get('kickstart_file') - ipxe_file = options.get('ipxe_file') - description = options.get('description') + kickstart_file = options.get("kickstart_file") + ipxe_file = options.get("ipxe_file") + description = options.get("description") if kickstart_file: - with open(kickstart_file, 'r') as file: + with open(kickstart_file, "r") as file: kickstart_file_data = file.read() else: kickstart_file_data = "" if ipxe_file: - with open(ipxe_file, 'r') as file: + with open(ipxe_file, "r") as file: ipxe_file_data = file.read() else: ipxe_file_data = "" - preboot_name = options.get('preboot_name') + preboot_name = options.get("preboot_name") self.create_preboot_configuration( kickstart_file_data, ipxe_file_data, preboot_name, description ) def add_arguments(self, parser): parser.add_argument( - '-k', '--kickstart-file', + "-k", + "--kickstart-file", default=None, - dest='kickstart_file', - help='Path to a file with kickstart content.' + dest="kickstart_file", + help="Path to a file with kickstart content.", ) parser.add_argument( - '-i', '--ipxe-file', + "-i", + "--ipxe-file", default=None, - dest='ipxe_file', - help='Path to a file with ipxe content.' + dest="ipxe_file", + help="Path to a file with ipxe content.", ) parser.add_argument( - '-d', '--description', + "-d", + "--description", default="Automatically generated preboot.", - dest='description', - help='Preboot description.' + dest="description", + help="Preboot description.", ) parser.add_argument( - '-n', '--preboot-configuration-name', + "-n", + "--preboot-configuration-name", default="Preboot", - dest='preboot_name', - help='Preboot configuration name.' + dest="preboot_name", + help="Preboot configuration name.", ) @classmethod @@ -64,11 +65,13 @@ def create_preboot_configuration( ): kickstart_file, _ = PrebootConfiguration.objects.get_or_create( name="{} kickstart".format(preboot_name), - type=PrebootItemType.kickstart.id, configuration=kickstart_file + type=PrebootItemType.kickstart.id, + configuration=kickstart_file, ) ipxe_file, _ = PrebootConfiguration.objects.get_or_create( name="{} ipxe".format(preboot_name), - type=PrebootItemType.ipxe.id, configuration=ipxe_file + type=PrebootItemType.ipxe.id, + configuration=ipxe_file, ) preboot, _ = Preboot.objects.get_or_create( name=preboot_name, description=description diff --git a/src/ralph/data_importer/management/commands/create_server_model.py b/src/ralph/data_importer/management/commands/create_server_model.py index c225b39aba..f3431f441c 100644 --- a/src/ralph/data_importer/management/commands/create_server_model.py +++ b/src/ralph/data_importer/management/commands/create_server_model.py @@ -1,71 +1,69 @@ from django.core.management import BaseCommand -from ralph.assets.models import ( - AssetModel, - Category, - Manufacturer, - ObjectModelType -) +from ralph.assets.models import AssetModel, Category, Manufacturer, ObjectModelType -DEFAULT_MODEL_CATEGORY = 'generic server category' -DEFAULT_MODEL_NAME = 'Model A' -DEFAULT_MODEL_MANUFACTURER = 'Generic manufacturer' +DEFAULT_MODEL_CATEGORY = "generic server category" +DEFAULT_MODEL_NAME = "Model A" +DEFAULT_MODEL_MANUFACTURER = "Generic manufacturer" class Command(BaseCommand): """ Generate a single, production ready server model """ + def handle(self, *args, **options): - model_name = options.get('model_name') - model_category = options.get('model_category') - model_manufacturer = options.get('model_manufacturer') - is_blade = options.get('model_is_blade_server') - self.create_model( - model_name, model_category, model_manufacturer, is_blade - ) + model_name = options.get("model_name") + model_category = options.get("model_category") + model_manufacturer = options.get("model_manufacturer") + is_blade = options.get("model_is_blade_server") + self.create_model(model_name, model_category, model_manufacturer, is_blade) def add_arguments(self, parser): parser.add_argument( - '-c', '--model-category', + "-c", + "--model-category", default=DEFAULT_MODEL_CATEGORY, - dest='model_category', - help='Server model category.' + dest="model_category", + help="Server model category.", ) parser.add_argument( - '-n', '--model-name', + "-n", + "--model-name", default=DEFAULT_MODEL_NAME, - dest='model_name', - help='Server model.' + dest="model_name", + help="Server model.", ) parser.add_argument( - '-m', '--model-manufacturer', + "-m", + "--model-manufacturer", default=DEFAULT_MODEL_MANUFACTURER, - dest='model_manufacturer', - help='Server model manufacturer.' + dest="model_manufacturer", + help="Server model manufacturer.", ) parser.add_argument( - '--model-is-blade-server', - action='store_true', - help='If set, model will be marked as blade server.' + "--model-is-blade-server", + action="store_true", + help="If set, model will be marked as blade server.", ) @classmethod def create_model( - cls, model_name=DEFAULT_MODEL_NAME, + cls, + model_name=DEFAULT_MODEL_NAME, model_category=DEFAULT_MODEL_CATEGORY, model_manufacturer=DEFAULT_MODEL_MANUFACTURER, - is_blade=False + is_blade=False, ): category, _ = Category.objects.get_or_create( name=model_category, allow_deployment=True ) - manufacturer, _ = Manufacturer.objects.get_or_create( - name=model_manufacturer - ) + manufacturer, _ = Manufacturer.objects.get_or_create(name=model_manufacturer) AssetModel.objects.get_or_create( - name=model_name, category=category, + name=model_name, + category=category, type=ObjectModelType.data_center.id, - manufacturer=manufacturer, has_parent=is_blade + manufacturer=manufacturer, + has_parent=is_blade, ) diff --git a/src/ralph/data_importer/management/commands/create_transitions.py b/src/ralph/data_importer/management/commands/create_transitions.py index 7882f87ec4..de2ddb4d4c 100644 --- a/src/ralph/data_importer/management/commands/create_transitions.py +++ b/src/ralph/data_importer/management/commands/create_transitions.py @@ -10,6 +10,7 @@ class Command(BaseCommand): """ Generate production ready Data Center Asset Transitions """ + def handle(self, *args, **options): self.create_data_center_asset_transitions() @@ -22,66 +23,61 @@ def create_data_center_asset_transitions(cls): DataCenterAssetStatus.free.id, DataCenterAssetStatus.damaged.id, DataCenterAssetStatus.liquidated.id, - DataCenterAssetStatus.to_deploy.id + DataCenterAssetStatus.to_deploy.id, ] cls.add_transition( content_type=content_type, - name='Deploy', + name="Deploy", source=source, actions=[ - 'assign_configuration_path', - 'assign_new_hostname', - 'assign_service_env', - 'clean_dhcp', - 'clean_hostname', - 'clean_ipaddresses', - 'cleanup_security_scans', - 'create_dhcp_entries', - 'create_dns_entries', - 'deploy', - 'wait_for_dhcp_servers', - 'wait_for_ping' - ] + "assign_configuration_path", + "assign_new_hostname", + "assign_service_env", + "clean_dhcp", + "clean_hostname", + "clean_ipaddresses", + "cleanup_security_scans", + "create_dhcp_entries", + "create_dns_entries", + "deploy", + "wait_for_dhcp_servers", + "wait_for_ping", + ], ) cls.add_transition( - name='Change config path', - actions=[ - 'assign_configuration_path' - ], + name="Change config path", + actions=["assign_configuration_path"], content_type=content_type, source=source, - async_service_name=None + async_service_name=None, ) cls.add_transition( - name='Reinstall', - actions=[ - 'deploy', - 'wait_for_ping' - ], + name="Reinstall", + actions=["deploy", "wait_for_ping"], content_type=content_type, - source=source + source=source, ) @classmethod def add_transition( - cls, content_type, name, source, actions, + cls, + content_type, + name, + source, + actions, async_service_name=DEFAULT_ASYNC_TRANSITION_SERVICE_NAME, - target=0 + target=0, ): transition, _ = Transition.objects.get_or_create( - model=TransitionModel.objects.get( - content_type=content_type - ), + model=TransitionModel.objects.get(content_type=content_type), name=name, source=source, target=target, - async_service_name=async_service_name + async_service_name=async_service_name, ) for action in actions: transition.actions.add( - Action.objects.get( - name=action, content_type=content_type - ) + Action.objects.get(name=action, content_type=content_type) ) diff --git a/src/ralph/data_importer/management/commands/demodata.py b/src/ralph/data_importer/management/commands/demodata.py index 573dc0bf9a..cff3dd4484 100644 --- a/src/ralph/data_importer/management/commands/demodata.py +++ b/src/ralph/data_importer/management/commands/demodata.py @@ -11,11 +11,7 @@ from django.core.management.base import BaseCommand from ralph.accounts.models import RalphUser -from ralph.accounts.tests.factories import ( - GroupFactory, - RegionFactory, - UserFactory -) +from ralph.accounts.tests.factories import GroupFactory, RegionFactory, UserFactory from ralph.assets.tests.factories import ( BackOfficeAssetModelFactory, BusinessSegmentFactory, @@ -23,7 +19,7 @@ DataCenterAssetModelFactory, DataCenterCategoryFactory, ProfitCenterFactory, - ServiceEnvironmentFactory + ServiceEnvironmentFactory, ) from ralph.back_office.models import BackOfficeAsset, BackOfficeAssetStatus from ralph.back_office.tests.factories import BackOfficeAssetFactory @@ -34,15 +30,16 @@ DataCenterAssetFactory, RackAccessoryFactory, RackFactory, - ServerRoomFactory + ServerRoomFactory, +) +from ralph.data_importer.management.commands.create_transitions import ( + Command as TransitionCommand, ) -from ralph.data_importer.management.commands.create_transitions import \ - Command as TransitionCommand from ralph.licences.models import LicenceUser from ralph.licences.tests.factories import ( BaseObjectLicenceFactory, DataCenterAssetLicenceFactory, - LicenceFactory + LicenceFactory, ) from ralph.reports.models import Report, ReportLanguage, ReportTemplate from ralph.supports.tests.factories import BaseObjectsSupportFactory @@ -53,47 +50,58 @@ def get_imei(n): """Random IMEI generator. This function return random but not unique IMEI number. Based on code from http://stackoverflow.com/a/20733310 """ + def luhn_residue(digits): """Luhn algorithm""" - return sum(sum(divmod(int(d) * (1 + i % 2), 10)) - for i, d in enumerate(digits[::-1])) % 10 + return ( + sum( + sum(divmod(int(d) * (1 + i % 2), 10)) + for i, d in enumerate(digits[::-1]) + ) + % 10 + ) - part = ''.join(str(random.randrange(0, 9)) for _ in range(n - 1)) - res = luhn_residue('{}{}'.format(part, 0)) - return '{}{}'.format(part, -res % 10) + part = "".join(str(random.randrange(0, 9)) for _ in range(n - 1)) + res = luhn_residue("{}{}".format(part, 0)) + return "{}{}".format(part, -res % 10) class Command(BaseCommand): - help = "Generating demo data." all_apps = [ - 'backoffice', 'datacenter', 'licences', 'supports', 'transitions', - 'sim_cards', 'cloudimages' + "backoffice", + "datacenter", + "licences", + "supports", + "transitions", + "sim_cards", + "cloudimages", ] object_limit = 30 def add_arguments(self, parser): parser.add_argument( - '-a', '--apps', - choices=self.all_apps + ['all'], - default='all', - dest='apps', - help='One or more apps separated by comma.' + "-a", + "--apps", + choices=self.all_apps + ["all"], + default="all", + dest="apps", + help="One or more apps separated by comma.", ) parser.add_argument( - '-f', '--flush', + "-f", + "--flush", default=False, - action='store_true', - dest='flush', - help='Flush database before generate.' + action="store_true", + dest="flush", + help="Flush database before generate.", ) def generate_data_center(self): - self.stdout.write('Generating Data Center assets') + self.stdout.write("Generating Data Center assets") data_center_status = DataCenterAssetStatus() parent_category = DataCenterCategoryFactory( - name='DATA CENTER', - imei_required=False + name="DATA CENTER", imei_required=False ) for i in range(2): server_room = ServerRoomFactory() @@ -103,13 +111,10 @@ def generate_data_center(self): rack = RackFactory( server_room=server_room, visualization_row=visualization_row, - visualization_col=visualization_col + visualization_col=visualization_col, ) visualization_row += 1 - if ( - visualization_row > - server_room.visualization_rows_num - ): + if visualization_row > server_room.visualization_rows_num: visualization_row = 1 visualization_col += 1 @@ -119,17 +124,15 @@ def generate_data_center(self): for status_id, name in data_center_status: for i in range(2): asset_model = DataCenterAssetModelFactory( - category=DataCenterCategoryFactory( - parent=parent_category - ) + category=DataCenterCategoryFactory(parent=parent_category) ) DataCenterAssetFactory( rack=rack, status=status_id, position=position, - slot_no='', + slot_no="", service_env=ServiceEnvironmentFactory(), - model=asset_model + model=asset_model, ) position += asset_model.height_of_device if position > rack.max_u_height: @@ -142,10 +145,10 @@ def generate_data_center(self): slot_no=None, service_env=ServiceEnvironmentFactory(), model=DataCenterAssetModelFactory( - name='Chassis', + name="Chassis", category=DataCenterCategoryFactory(parent=parent_category), - height_of_device=5 - ) + height_of_device=5, + ), ) for i in range(5): DataCenterAssetFactory( @@ -156,22 +159,17 @@ def generate_data_center(self): slot_no=i, parent=chassis, model=DataCenterAssetModelFactory( - name='Blade', + name="Blade", has_parent=True, - category=DataCenterCategoryFactory( - parent=parent_category - ) - ) + category=DataCenterCategoryFactory(parent=parent_category), + ), ) def generate_back_office(self): - self.stdout.write('Generating Back Office assets') + self.stdout.write("Generating Back Office assets") back_office_status = BackOfficeAssetStatus() per_page = 2 - parent_category = CategoryFactory( - name='BACK OFFICE', - imei_required=False - ) + parent_category = CategoryFactory(name="BACK OFFICE", imei_required=False) for i in range(3): ProfitCenterFactory() BusinessSegmentFactory() @@ -184,7 +182,7 @@ def generate_back_office(self): owner=self.get_user(), model=BackOfficeAssetModelFactory( category=CategoryFactory(parent=parent_category) - ) + ), ) BackOfficeAssetFactory( status=status_id, @@ -192,114 +190,102 @@ def generate_back_office(self): owner=self.get_user(), model=BackOfficeAssetModelFactory( category=CategoryFactory( - name='Mobile Phone', + name="Mobile Phone", imei_required=True, - parent=parent_category + parent=parent_category, ), - name='Phone' + name="Phone", ), imei=get_imei(15), - imei2=get_imei(15) + imei2=get_imei(15), ) def generate_users_and_groups(self): - self.stdout.write('Generating Users and Groups') + self.stdout.write("Generating Users and Groups") - def add_user_and_group( - username, password, group_name, permission_models - ): + def add_user_and_group(username, password, group_name, permission_models): group = GroupFactory(name=group_name) for permision_model in permission_models: for perm in Permission.objects.filter( content_type=ContentType.objects.get_by_natural_key( - *permision_model.split('.') + *permision_model.split(".") ) ): group.permissions.add(perm) - user = UserFactory( - username=username, - is_staff=True - ) + user = UserFactory(username=username, is_staff=True) user.regions.add(RegionFactory()) user.set_password(password) user.groups.add(group) user.save() dc_permission_models = [ - 'accounts.region', - 'assets.assetmodel', - 'assets.environment', - 'assets.service', - 'assets.serviceenvironment', - 'data_center.accessory', - 'data_center.database', - 'data_center.datacenter', - 'data_center.datacenterasset', - 'data_center.rack', - 'data_center.rackaccessory', - 'data_center.serverroom', - 'licences.licence', - 'networks.ipaddress', - 'supports.support', - 'virtual.virtualserver' + "accounts.region", + "assets.assetmodel", + "assets.environment", + "assets.service", + "assets.serviceenvironment", + "data_center.accessory", + "data_center.database", + "data_center.datacenter", + "data_center.datacenterasset", + "data_center.rack", + "data_center.rackaccessory", + "data_center.serverroom", + "licences.licence", + "networks.ipaddress", + "supports.support", + "virtual.virtualserver", ] - add_user_and_group( - 'dc', 'dc', 'Data Center Group', dc_permission_models - ) + add_user_and_group("dc", "dc", "Data Center Group", dc_permission_models) bo_permission_models = [ - 'accounts.ralphuser', - 'accounts.region', - 'assets.asset', - 'assets.assetholder', - 'assets.assetmodel', - 'assets.baseobject', - 'assets.budgetinfo', - 'assets.category', - 'assets.manufacturer', - 'assets.profitcenter', - 'attachments.attachment', - 'attachments.attachmentitem', - 'back_office.backofficeasset', - 'back_office.officeinfrastructure', - 'back_office.warehouse', - 'licences.baseobjectlicence', - 'licences.licence', - 'licences.licencetype', - 'licences.licenceuser', - 'reports.reportlanguage', - 'reports.reporttemplate', - 'supports.baseobjectssupport', - 'supports.support', - 'supports.supporttype', - 'transitions.transition' + "accounts.ralphuser", + "accounts.region", + "assets.asset", + "assets.assetholder", + "assets.assetmodel", + "assets.baseobject", + "assets.budgetinfo", + "assets.category", + "assets.manufacturer", + "assets.profitcenter", + "attachments.attachment", + "attachments.attachmentitem", + "back_office.backofficeasset", + "back_office.officeinfrastructure", + "back_office.warehouse", + "licences.baseobjectlicence", + "licences.licence", + "licences.licencetype", + "licences.licenceuser", + "reports.reportlanguage", + "reports.reporttemplate", + "supports.baseobjectssupport", + "supports.support", + "supports.supporttype", + "transitions.transition", ] - add_user_and_group( - 'bo', 'bo', 'Back Office Group', bo_permission_models - ) + add_user_and_group("bo", "bo", "Back Office Group", bo_permission_models) def generate_transitions(self): - self.stdout.write('Generating Transitions') + self.stdout.write("Generating Transitions") - report = Report.objects.create(name='release') - language = ReportLanguage.objects.create(name='en', default=True) + report = Report.objects.create(name="release") + language = ReportLanguage.objects.create(name="en", default=True) report_template = ReportTemplate.objects.create( - language=language, - default=True, - report=report + language=language, default=True, report=report ) with open( - os.path.join(settings.BASE_DIR, 'data_importer/data/release.odt'), - 'rb' + os.path.join(settings.BASE_DIR, "data_importer/data/release.odt"), "rb" ) as f: - report_template.template.save('release.odt', File(f)) + report_template.template.save("release.odt", File(f)) bo_content_type = ContentType.objects.get_for_model(BackOfficeAsset) TransitionCommand.add_transition( content_type=bo_content_type, - name='Deploy', + name="Deploy", source=[ BackOfficeAssetStatus.new.id, BackOfficeAssetStatus.in_progress.id, @@ -310,77 +296,82 @@ def generate_transitions(self): BackOfficeAssetStatus.in_service.id, BackOfficeAssetStatus.installed.id, BackOfficeAssetStatus.free.id, - BackOfficeAssetStatus.reserved.id + BackOfficeAssetStatus.reserved.id, ], target=BackOfficeAssetStatus.in_progress.id, - actions=['assign_licence', 'assign_user', 'assign_owner'] + actions=["assign_licence", "assign_user", "assign_owner"], ) TransitionCommand.add_transition( content_type=bo_content_type, - name='Release asset', + name="Release asset", source=[ BackOfficeAssetStatus.new.id, BackOfficeAssetStatus.in_progress.id, BackOfficeAssetStatus.waiting_for_release.id, BackOfficeAssetStatus.free.id, - BackOfficeAssetStatus.reserved.id + BackOfficeAssetStatus.reserved.id, ], target=BackOfficeAssetStatus.used.id, actions=[ - 'assign_user', 'assign_owner', 'assign_warehouse', - 'release_report' - ] + "assign_user", + "assign_owner", + "assign_warehouse", + "release_report", + ], ) TransitionCommand.add_transition( content_type=bo_content_type, - name='Loan asset', + name="Loan asset", source=[ BackOfficeAssetStatus.new.id, BackOfficeAssetStatus.in_progress.id, BackOfficeAssetStatus.waiting_for_release.id, BackOfficeAssetStatus.free.id, - BackOfficeAssetStatus.reserved.id + BackOfficeAssetStatus.reserved.id, ], target=BackOfficeAssetStatus.loan.id, actions=[ - 'assign_loan_end_date', 'assign_user', 'assign_owner', - 'assign_warehouse', 'assign_task_url' - ] + "assign_loan_end_date", + "assign_user", + "assign_owner", + "assign_warehouse", + "assign_task_url", + ], ) TransitionCommand.add_transition( content_type=bo_content_type, - name='Buyout', + name="Buyout", source=[i[0] for i in BackOfficeAssetStatus()], target=BackOfficeAssetStatus.liquidated.id, actions=[ - 'assign_task_url', 'assign_warehouse', 'assign_warehouse', - 'unassign_licences', 'unassign_loan_end_date', - 'unassign_owner', - ] + "assign_task_url", + "assign_warehouse", + "assign_warehouse", + "unassign_licences", + "unassign_loan_end_date", + "unassign_owner", + ], ) dc_content_type = ContentType.objects.get_for_model(DataCenterAsset) TransitionCommand.add_transition( content_type=dc_content_type, - name='Change rack', + name="Change rack", source=[ DataCenterAssetStatus.free.id, DataCenterAssetStatus.new.id, DataCenterAssetStatus.to_deploy.id, ], target=DataCenterAssetStatus.used.id, - actions=['change_rack'] + actions=["change_rack"], ) def generate_licence(self): - self.stdout.write('Generating Licences') + self.stdout.write("Generating Licences") for i in range(self.object_limit): licence = LicenceFactory() - LicenceUser.objects.create( - licence=licence, - user=self.get_user() - ) + LicenceUser.objects.create(licence=licence, user=self.get_user()) for j in range(3): back_office_asset = BaseObjectLicenceFactory( licence=licence @@ -390,14 +381,9 @@ def generate_licence(self): back_office_asset.save() licence = LicenceFactory() - LicenceUser.objects.create( - licence=licence, - user=self.get_user() - ) + LicenceUser.objects.create(licence=licence, user=self.get_user()) for j in range(3): - DataCenterAssetLicenceFactory( - licence=licence - ) + DataCenterAssetLicenceFactory(licence=licence) def generate_users(self): for i in range(self.object_limit): @@ -405,12 +391,12 @@ def generate_users(self): return RalphUser.objects.all() def get_user(self): - if not getattr(self, 'users', False): + if not getattr(self, "users", False): self.users = cycle(self.generate_users()) return next(self.users) def generate_support(self): - self.stdout.write('Generating Supports') + self.stdout.write("Generating Supports") for i in range(self.object_limit): # BaseObjectsSupportFactory automatically generates Support for j in range(3): @@ -420,40 +406,40 @@ def generate_support(self): back_office_asset.save() def generate_cloud_images(self): - self.stdout.write('Generating Cloud Images') + self.stdout.write("Generating Cloud Images") for i in range(self.object_limit): CloudImageFactory() def handle(self, *args, **options): - apps = options.get('apps').split(',') - if 'all' in apps: + apps = options.get("apps").split(",") + if "all" in apps: apps = self.all_apps - if options.get('flush', False): - self.stdout.write('Flush database..') - call_command('flush', interactive=False) - self.stdout.write('Flush finished.') + if options.get("flush", False): + self.stdout.write("Flush database..") + call_command("flush", interactive=False) + self.stdout.write("Flush finished.") self.generate_users_and_groups() - if 'backoffice' in apps: + if "backoffice" in apps: self.generate_back_office() - if 'datacenter' in apps: + if "datacenter" in apps: self.generate_data_center() - if 'supports' in apps: + if "supports" in apps: self.generate_support() - if 'licences' in apps: + if "licences" in apps: self.generate_licence() - if 'transitions' in apps: + if "transitions" in apps: self.generate_transitions() - if 'cloudimages' in apps: + if "cloudimages" in apps: self.generate_cloud_images() # Create super user - root = UserFactory(username='ralph', is_superuser=True, is_staff=True) - root.set_password('ralph') + root = UserFactory(username="ralph", is_superuser=True, is_staff=True) + root.set_password("ralph") root.save() - if options.get('flush', False): - call_command('sitetree_resync_apps', interactive=False) - self.stdout.write('done') + if options.get("flush", False): + call_command("sitetree_resync_apps", interactive=False) + self.stdout.write("done") diff --git a/src/ralph/data_importer/management/commands/import_attachments.py b/src/ralph/data_importer/management/commands/import_attachments.py index a5fb6e8013..8ec0385f4b 100644 --- a/src/ralph/data_importer/management/commands/import_attachments.py +++ b/src/ralph/data_importer/management/commands/import_attachments.py @@ -16,10 +16,7 @@ from ralph.attachments.models import Attachment, AttachmentItem from ralph.back_office.models import BackOfficeAsset from ralph.data_center.models.physical import DataCenterAsset -from ralph.data_importer.models import ( - ImportedObjectDoesNotExist, - ImportedObjects -) +from ralph.data_importer.models import ImportedObjectDoesNotExist, ImportedObjects from ralph.lib.transitions.models import TransitionsHistory from ralph.licences.models import Licence from ralph.supports.models import Support @@ -28,54 +25,50 @@ logger = logging.getLogger(__name__) MODELS_MAP = { - 'BackOfficeAsset': BackOfficeAsset, - 'DataCenterAsset': DataCenterAsset, - 'Support': Support, - 'Licence': Licence + "BackOfficeAsset": BackOfficeAsset, + "DataCenterAsset": DataCenterAsset, + "Support": Support, + "Licence": Licence, } class Command(BaseCommand): - help = "Imports attachments and Transition History" def add_arguments(self, parser): parser.add_argument( - 'source', - help='zip source location', + "source", + help="zip source location", ) parser.add_argument( - '-i', '--import', - choices=['attachments', 'transitionshistory', 'all'], - default='all', - dest='import' + "-i", + "--import", + choices=["attachments", "transitionshistory", "all"], + default="all", + dest="import", ) def save_transition_history(self, directory): - with open(os.path.join(directory, 'transition_history.csv')) as f: - reader = csv.reader(f, delimiter=',') + with open(os.path.join(directory, "transition_history.csv")) as f: + reader = csv.reader(f, delimiter=",") csv_data = list(reader) headers, csv_body = csv_data[0], csv_data[1:] dataset = tablib.Dataset(*csv_body, headers=headers) for line in dataset.dict: - model = MODELS_MAP.get(line.get('asset_type')) + model = MODELS_MAP.get(line.get("asset_type")) try: obj = ImportedObjects.get_object_from_old_pk( - model, line.get('asset') + model, line.get("asset") ) except ImportedObjectDoesNotExist: - logger.warning( - 'Missing imported object for %s', line - ) + logger.warning("Missing imported object for %s", line) continue logged_user, _ = get_user_model().objects.get_or_create( - username=line.get('logged_user') + username=line.get("logged_user") ) new_history = False - old_history_id = '{}|{}'.format( - line.get('id'), line.get('asset') - ) + old_history_id = "{}|{}".format(line.get("id"), line.get("asset")) try: history = ImportedObjects.get_object_from_old_pk( TransitionsHistory, old_history_id @@ -84,25 +77,23 @@ def save_transition_history(self, directory): history = TransitionsHistory() new_history = True - history.content_type = ContentType.objects.get_for_model( - model - ) - history.created = line.get('created') - history.modified = line.get('modified') + history.content_type = ContentType.objects.get_for_model(model) + history.created = line.get("created") + history.modified = line.get("modified") history.logged_user = logged_user - history.transition_name = line.get('transition') - history.kwargs = json.loads(line.get('kwargs', {})) + history.transition_name = line.get("transition") + history.kwargs = json.loads(line.get("kwargs", {})) actions = [ - i.replace('_', ' ').capitalize() - for i in line.get('actions').split(',') + i.replace("_", " ").capitalize() + for i in line.get("actions").split(",") ] history.actions = actions history.object_id = obj.pk - if line.get('report_filename_md5'): + if line.get("report_filename_md5"): try: history.attachment = Attachment.objects.get( - md5=line.get('report_filename_md5') + md5=line.get("report_filename_md5") ) except Attachment.DoesNotExist: try: @@ -110,11 +101,11 @@ def save_transition_history(self, directory): obj, os.path.join( directory, - 'transition_history', - 'assets', - line.get('report_filename') + "transition_history", + "assets", + line.get("report_filename"), ), - owner=logged_user + owner=logged_user, ) history.attachment = attachment except FileNotFoundError: @@ -124,45 +115,40 @@ def save_transition_history(self, directory): # update history record using update method to skip auto_now # and auto_now_add fields checks TransitionsHistory.objects.filter(pk=history.pk).update( - created=line.get('created'), - modified=line.get('modified'), + created=line.get("created"), + modified=line.get("modified"), ) if new_history: ImportedObjects.create(history, old_history_id) def save_attachments(self, directory): - with open(os.path.join(directory, 'attachments.csv')) as f: - reader = csv.reader(f, delimiter=',') + with open(os.path.join(directory, "attachments.csv")) as f: + reader = csv.reader(f, delimiter=",") csv_data = list(reader) headers, csv_body = csv_data[0], csv_data[1:] dataset = tablib.Dataset(*csv_body, headers=headers) for line in dataset.dict: - model = MODELS_MAP.get(line.get('parent_type'), None) + model = MODELS_MAP.get(line.get("parent_type"), None) if model: try: obj = ImportedObjects.get_object_from_old_pk( - model, line.get('parents') + model, line.get("parents") ) except ImportedObjectDoesNotExist: - logger.warning( - 'Missing imported object for %s', line - ) + logger.warning("Missing imported object for %s", line) continue - if line.get('md5'): + if line.get("md5"): owner, _ = get_user_model().objects.get_or_create( - username=line.get('uploaded_by') + username=line.get("uploaded_by") ) try: - attachment = Attachment.objects.get( - md5=line.get('md5') - ) + attachment = Attachment.objects.get(md5=line.get("md5")) content_type = ContentType.objects.get_for_model( obj._meta.model ) items = attachment.items.filter( - object_id=obj.pk, - content_type=content_type + object_id=obj.pk, content_type=content_type ) if not items: AttachmentItem.objects.attach( @@ -174,35 +160,25 @@ def save_attachments(self, directory): attachment = add_attachment_from_disk( obj, - os.path.join( - directory, - 'attachments', - line.get('file') - ), - owner=owner - ) - attachment.original_filename = line.get( - 'original_filename' - ) - attachment.save( - update_fields=['original_filename'] + os.path.join(directory, "attachments", line.get("file")), + owner=owner, ) + attachment.original_filename = line.get("original_filename") + attachment.save(update_fields=["original_filename"]) def handle(self, *args, **options): - source_file = options.get('source') - with open(source_file, 'rb') as f: + source_file = options.get("source") + with open(source_file, "rb") as f: out_path = tempfile.mkdtemp() z = zipfile.ZipFile(f) for name in z.namelist(): z.extract(name, out_path) - import_type = options.get('import') - if import_type == 'attachments' or import_type == 'all': - self.stdout.write( - 'Import Attachments from: {}'.format(source_file) - ) + import_type = options.get("import") + if import_type == "attachments" or import_type == "all": + self.stdout.write("Import Attachments from: {}".format(source_file)) self.save_attachments(out_path) - if import_type == 'transitionshistory' or import_type == 'all': + if import_type == "transitionshistory" or import_type == "all": self.stdout.write( - 'Import TransitionHistory from: {}'.format(source_file) + "Import TransitionHistory from: {}".format(source_file) ) self.save_transition_history(out_path) diff --git a/src/ralph/data_importer/management/commands/importer.py b/src/ralph/data_importer/management/commands/importer.py index ebf081c18d..1659d3cc5e 100644 --- a/src/ralph/data_importer/management/commands/importer.py +++ b/src/ralph/data_importer/management/commands/importer.py @@ -23,86 +23,81 @@ def get_resource(model_name): """Return resource for import model.""" - resource_name = model_name + 'Resource' + resource_name = model_name + "Resource" resource = getattr(ralph_resources, resource_name, None) if not resource: model_class = APP_MODELS[model_name.lower()] resource = resources.modelresource_factory( - model=model_class, - resource_class=RalphModelResource + model=model_class, resource_class=RalphModelResource ) return resource() class Command(BaseCommand): - help = "Imports data for specified model from specified file" def add_arguments(self, parser): parser.add_argument( - '--model_name', - help='The model name to which the import data', + "--model_name", + help="The model name to which the import data", ) parser.add_argument( - 'source', - help='file, zip or dir source location', + "source", + help="file, zip or dir source location", ) parser.add_argument( - '--skipid', - action='store_true', + "--skipid", + action="store_true", default=False, help="Remove ID value from rows", ) parser.add_argument( - '-t', '--type', - choices=['file', 'dir', 'zip'], - default='file', - dest='type' + "-t", "--type", choices=["file", "dir", "zip"], default="file", dest="type" ) parser.add_argument( - '-d', '--delimiter', - dest='delimiter', - default=',', + "-d", + "--delimiter", + dest="delimiter", + default=",", help="Delimiter for csv file", ) parser.add_argument( - '-e', '--encoding', - dest='encoding', - default='utf-8', + "-e", + "--encoding", + dest="encoding", + default="utf-8", help="Output encoding", ) parser.add_argument( - '--map-imported-id-to-new-id', - dest='map_imported_id_to_new_id', + "--map-imported-id-to-new-id", + dest="map_imported_id_to_new_id", default=False, - action='store_true', + action="store_true", help="Use it when importing data from Ralph 2.", ) def from_zip(self, options): - with open(options.get('source'), 'rb') as f: + with open(options.get("source"), "rb") as f: out_path = tempfile.mkdtemp() z = zipfile.ZipFile(f) for name in z.namelist(): z.extract(name, out_path) - options['source'] = out_path + options["source"] = out_path self.from_dir(options) def from_dir(self, options): file_list = [] - for path in glob.glob(os.path.join(options.get('source'), '*.csv')): + for path in glob.glob(os.path.join(options.get("source"), "*.csv")): base_name = os.path.basename(path) - file_name = os.path.splitext(base_name)[0].split('_') - file_list.append({ - 'model': file_name[1], - 'path': path, - 'sort': int(file_name[0]) - }) - file_list = sorted(file_list, key=lambda x: x['sort']) + file_name = os.path.splitext(base_name)[0].split("_") + file_list.append( + {"model": file_name[1], "path": path, "sort": int(file_name[0])} + ) + file_list = sorted(file_list, key=lambda x: x["sort"]) for item in file_list: - logger.info('Import to model: {}'.format(item['model'])) - options['model_name'] = item['model'] - options['source'] = item['path'] + logger.info("Import to model: {}".format(item["model"])) + options["model_name"] = item["model"] + options["source"] = item["path"] self.from_file(options) def delete_objs(self, data, model): @@ -111,85 +106,74 @@ def delete_objs(self, data, model): revision_manager = reversion.default_revision_manager if not old_id: continue - obj = ImportedObjects.get_object_from_old_pk( - model, int(old_id) - ) - revision_manager.save_revision( - (obj,), comment='Imported from old Ralph' - ) + obj = ImportedObjects.get_object_from_old_pk(model, int(old_id)) + revision_manager.save_revision((obj,), comment="Imported from old Ralph") with reversion.create_revision(): obj.delete() counter += 1 return counter def from_file(self, options): - if not options.get('model_name'): - raise CommandError('You must select a model') - csv.register_dialect( - "RalphImporter", - delimiter=str(options['delimiter']) + if not options.get("model_name"): + raise CommandError("You must select a model") + csv.register_dialect("RalphImporter", delimiter=str(options["delimiter"])) + settings.REMOVE_ID_FROM_IMPORT = options.get("skipid") + self.stdout.write( + "Import {} resource from {}".format( + options.get("model_name"), options.get("source") + ) ) - settings.REMOVE_ID_FROM_IMPORT = options.get('skipid') - self.stdout.write('Import {} resource from {}'.format( - options.get('model_name'), - options.get('source') - )) - with open(options.get('source')) as csv_file: + with open(options.get("source")) as csv_file: reader_kwargs = {} - reader = csv.reader( - csv_file, - dialect='RalphImporter', - **reader_kwargs - ) + reader = csv.reader(csv_file, dialect="RalphImporter", **reader_kwargs) csv_data = list(reader) headers, csv_body = csv_data[0], csv_data[1:] - model_resource = get_resource(options.get('model_name')) + model_resource = get_resource(options.get("model_name")) before_import = model_resource._meta.model.objects.count() dataset = tablib.Dataset(*csv_body, headers=headers) objs_delete = [ - obj.get('id', None) for obj in dataset.dict - if int(obj.get('deleted', 0)) == 1 + obj.get("id", None) + for obj in dataset.dict + if int(obj.get("deleted", 0)) == 1 ] result = model_resource.import_data(dataset, dry_run=False) if result.has_errors(): for idx, row in enumerate(result.rows): for error in row.errors: - error_msg = '\n'.join([ - 'line_number: {}'.format(idx + 1), - 'error message: {}'.format(error.error), - 'row data: {}'.format( - list(zip(headers, dataset[idx])) - ), - '', - ]) + error_msg = "\n".join( + [ + "line_number: {}".format(idx + 1), + "error message: {}".format(error.error), + "row data: {}".format(list(zip(headers, dataset[idx]))), + "", + ] + ) self.stderr.write(error_msg) if row.errors: break after_import_count = model_resource._meta.model.objects.count() self.stderr.write( - 'Imported records: {}'.format( - after_import_count - before_import - ) + "Imported records: {}".format(after_import_count - before_import) ) - if (len(csv_body) - after_import_count - before_import >= 0): + if len(csv_body) - after_import_count - before_import >= 0: self.stderr.write( - 'Skipped records: {}'.format( + "Skipped records: {}".format( len(csv_body) - after_import_count - before_import ) ) deleted = self.delete_objs(objs_delete, model_resource._meta.model) - self.stdout.write('{} deleted\n'.format(deleted)) - self.stdout.write('Done\n') + self.stdout.write("{} deleted\n".format(deleted)) + self.stdout.write("Done\n") def handle(self, *args, **options): - if options.get('map_imported_id_to_new_id'): + if options.get("map_imported_id_to_new_id"): settings.MAP_IMPORTED_ID_TO_NEW_ID = True settings.CHECK_IP_HOSTNAME_ON_SAVE = False - if options.get('type') == 'dir': + if options.get("type") == "dir": self.from_dir(options) - elif options.get('type') == 'zip': + elif options.get("type") == "zip": self.from_zip(options) else: self.from_file(options) diff --git a/src/ralph/data_importer/management/commands/initial_data.py b/src/ralph/data_importer/management/commands/initial_data.py index 3c46eadcf3..d5385d0287 100644 --- a/src/ralph/data_importer/management/commands/initial_data.py +++ b/src/ralph/data_importer/management/commands/initial_data.py @@ -6,32 +6,34 @@ from ralph.accounts.tests.factories import RegionFactory from ralph.assets.models import ConfigurationClass, ConfigurationModule -from ralph.data_importer.management.commands.create_network import \ - Command as NetworkCommand -from ralph.data_importer.management.commands.create_server_model import \ - Command as ServerModelCommand -from ralph.data_importer.management.commands.create_transitions import \ - Command as TransitionsCommand +from ralph.data_importer.management.commands.create_network import ( + Command as NetworkCommand, +) +from ralph.data_importer.management.commands.create_server_model import ( + Command as ServerModelCommand, +) +from ralph.data_importer.management.commands.create_transitions import ( + Command as TransitionsCommand, +) class Command(BaseCommand): """ Generate data useful to start a fresh and empty Ralph instance. """ + @transaction.atomic def handle(self, *args, **options): try: - parent_network = ipaddress.ip_network( - options.get('parent_network') - ) - dc_name = options.get('dc_name') - server_room_name = options.get('server_room_name') + parent_network = ipaddress.ip_network(options.get("parent_network")) + dc_name = options.get("dc_name") + server_room_name = options.get("server_room_name") network_address = parent_network.network_address - dns_1 = ipaddress.ip_address(options.get('dns_1')) - dns_2 = ipaddress.ip_address(options.get('dns_2')) - number_of_subnets = int(options.get('number_of_subnets')) - region = options.get('region') - configuration_path = options.get('configuration_path') + dns_1 = ipaddress.ip_address(options.get("dns_1")) + dns_2 = ipaddress.ip_address(options.get("dns_2")) + number_of_subnets = int(options.get("number_of_subnets")) + region = options.get("region") + configuration_path = options.get("configuration_path") except ValueError as e: raise CommandError(e) @@ -48,10 +50,10 @@ def handle(self, *args, **options): dns2_address=dns_2, gateway_address=network_address + 1, network=parent_network, - server_room_name=server_room_name + server_room_name=server_room_name, ) for _ in range(0, number_of_subnets): - network = ipaddress.ip_network('{}/{}'.format(network_address, 24)) + network = ipaddress.ip_network("{}/{}".format(network_address, 24)) NetworkCommand.create_network( dc_name=dc_name, dns1_address=dns_1, @@ -59,69 +61,62 @@ def handle(self, *args, **options): gateway_address=network_address + 1, network=network, server_room_name=server_room_name, - create_rack=True + create_rack=True, ) network_address += 256 for name in ["A", "B", "C"]: + ServerModelCommand.create_model(model_name="Model {}".format(name)) ServerModelCommand.create_model( - model_name="Model {}".format(name) - ) - ServerModelCommand.create_model( - model_name="Blade server model {}".format(name), - is_blade=True + model_name="Blade server model {}".format(name), is_blade=True ) - call_command('sitetree_resync_apps') + call_command("sitetree_resync_apps") def add_arguments(self, parser): parser.add_argument( - '-d', '--dc-name', - default='dc1', - dest='dc_name', - help='Data center name.' + "-d", "--dc-name", default="dc1", dest="dc_name", help="Data center name." ) parser.add_argument( - '-s', '--server-room-name', - default='server room', - dest='server_room_name', - help='Server room name.' + "-s", + "--server-room-name", + default="server room", + dest="server_room_name", + help="Server room name.", ) parser.add_argument( - '-p', '--parent-network', - default='10.0.0.0/16', - dest='parent_network', - help='Parent network address.' + "-p", + "--parent-network", + default="10.0.0.0/16", + dest="parent_network", + help="Parent network address.", ) parser.add_argument( - '--dns1', - default='10.0.0.11', - dest='dns_1', - help='Primary DNS server.' + "--dns1", default="10.0.0.11", dest="dns_1", help="Primary DNS server." ) parser.add_argument( - '--dns2', - default='10.0.0.12', - dest='dns_2', - help='Secondary DNS server.' + "--dns2", default="10.0.0.12", dest="dns_2", help="Secondary DNS server." ) parser.add_argument( - '-n', '--number-of-subnets', - default='3', - dest='number_of_subnets', - help='Number of /24 subnets to be generated.' + "-n", + "--number-of-subnets", + default="3", + dest="number_of_subnets", + help="Number of /24 subnets to be generated.", ) parser.add_argument( - '-r', '--region', - default='PL', - dest='region', - help='Geographical region (eg. your location).' + "-r", + "--region", + default="PL", + dest="region", + help="Geographical region (eg. your location).", ) parser.add_argument( - '-c', '--configuration-path', - default='configuration_module/default', - dest='configuration_path', - help='Default configuration path.' + "-c", + "--configuration-path", + default="configuration_module/default", + dest="configuration_path", + help="Default configuration path.", ) def _validate_network(self, network, number_of_subnets): @@ -132,14 +127,12 @@ def _validate_network(self, network, number_of_subnets): network, number_of_subnets ) ) - max_netmask = ipaddress.ip_address('255.255.254.0') + max_netmask = ipaddress.ip_address("255.255.254.0") if network.netmask > max_netmask: - raise CommandError( - "Net mask must be /23 or less." - ) + raise CommandError("Net mask must be /23 or less.") def _validate_configuration_path(self, configuration_path): - if len(configuration_path.split('/')) != 2: + if len(configuration_path.split("/")) != 2: raise CommandError( "Configuration path must be a string with no spaces including" "one slash." @@ -148,17 +141,13 @@ def _validate_configuration_path(self, configuration_path): def create_users(self, region): user_model = get_user_model() user, _ = user_model.objects.get_or_create( - username='admin', is_staff=True, is_superuser=True + username="admin", is_staff=True, is_superuser=True ) user.regions.add(RegionFactory(name=region)) - user.set_password('admin') + user.set_password("admin") user.save() def create_configuration_path(self, configuration_path): - configuration_module, configuration_class = configuration_path.split( - '/' - ) + configuration_module, configuration_class = configuration_path.split("/") module = ConfigurationModule.objects.create(name=configuration_module) - ConfigurationClass.objects.create( - class_name=configuration_class, module=module - ) + ConfigurationClass.objects.create(class_name=configuration_class, module=module) diff --git a/src/ralph/data_importer/migrations/0001_initial.py b/src/ralph/data_importer/migrations/0001_initial.py index 6a6be53516..c4f8b8fe1f 100644 --- a/src/ralph/data_importer/migrations/0001_initial.py +++ b/src/ralph/data_importer/migrations/0001_initial.py @@ -6,25 +6,46 @@ class Migration(migrations.Migration): - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), + ("contenttypes", "0002_remove_content_type_name"), ] operations = [ migrations.CreateModel( - name='ImportedObjects', + name="ImportedObjects", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('object_pk', models.IntegerField(db_index=True)), - ('old_object_pk', models.CharField(db_index=True, max_length=255)), - ('content_type', models.ForeignKey(to='contenttypes.ContentType', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ("object_pk", models.IntegerField(db_index=True)), + ("old_object_pk", models.CharField(db_index=True, max_length=255)), + ( + "content_type", + models.ForeignKey( + to="contenttypes.ContentType", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, - 'ordering': ('-modified', '-created'), + "abstract": False, + "ordering": ("-modified", "-created"), }, ), ] diff --git a/src/ralph/data_importer/migrations/0002_auto_20151125_1354.py b/src/ralph/data_importer/migrations/0002_auto_20151125_1354.py index 1cbd3530ab..74bfb643c8 100644 --- a/src/ralph/data_importer/migrations/0002_auto_20151125_1354.py +++ b/src/ralph/data_importer/migrations/0002_auto_20151125_1354.py @@ -5,20 +5,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_importer', '0001_initial'), + ("data_importer", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='importedobjects', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="importedobjects", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='importedobjects', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="importedobjects", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), ] diff --git a/src/ralph/data_importer/migrations/0003_auto_20160624_1217.py b/src/ralph/data_importer/migrations/0003_auto_20160624_1217.py index e09ddf6751..3728a2f388 100644 --- a/src/ralph/data_importer/migrations/0003_auto_20160624_1217.py +++ b/src/ralph/data_importer/migrations/0003_auto_20160624_1217.py @@ -1,22 +1,21 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('data_importer', '0002_auto_20151125_1354'), + ("data_importer", "0002_auto_20151125_1354"), ] operations = [ migrations.AlterModelOptions( - name='importedobjects', + name="importedobjects", options={}, ), migrations.AlterUniqueTogether( - name='importedobjects', - unique_together=set([('content_type', 'object_pk', 'old_object_pk')]), + name="importedobjects", + unique_together=set([("content_type", "object_pk", "old_object_pk")]), ), ] diff --git a/src/ralph/data_importer/migrations/0004_auto_20160728_1046.py b/src/ralph/data_importer/migrations/0004_auto_20160728_1046.py index 2fc8c47b7c..b26aa4be4c 100644 --- a/src/ralph/data_importer/migrations/0004_auto_20160728_1046.py +++ b/src/ralph/data_importer/migrations/0004_auto_20160728_1046.py @@ -1,18 +1,19 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('data_importer', '0003_auto_20160624_1217'), + ("data_importer", "0003_auto_20160624_1217"), ] operations = [ migrations.AlterUniqueTogether( - name='importedobjects', - unique_together=set([('content_type', 'object_pk'), ('content_type', 'old_object_pk')]), + name="importedobjects", + unique_together=set( + [("content_type", "object_pk"), ("content_type", "old_object_pk")] + ), ), ] diff --git a/src/ralph/data_importer/migrations/0005_importedobjects_old_ci_uid.py b/src/ralph/data_importer/migrations/0005_importedobjects_old_ci_uid.py index a8f3a95c59..ed788ec644 100644 --- a/src/ralph/data_importer/migrations/0005_importedobjects_old_ci_uid.py +++ b/src/ralph/data_importer/migrations/0005_importedobjects_old_ci_uid.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_importer', '0004_auto_20160728_1046'), + ("data_importer", "0004_auto_20160728_1046"), ] operations = [ migrations.AddField( - model_name='importedobjects', - name='old_ci_uid', - field=models.CharField(max_length=255, null=True, blank=True, db_index=True), + model_name="importedobjects", + name="old_ci_uid", + field=models.CharField( + max_length=255, null=True, blank=True, db_index=True + ), ), ] diff --git a/src/ralph/data_importer/mixins.py b/src/ralph/data_importer/mixins.py index cd0ea70755..a49f5fdd3f 100644 --- a/src/ralph/data_importer/mixins.py +++ b/src/ralph/data_importer/mixins.py @@ -10,7 +10,7 @@ ExportForeignKeyStrWidget, ExportManyToManyStrTroughWidget, ExportManyToManyStrWidget, - ManyToManyThroughWidget + ManyToManyThroughWidget, ) @@ -21,35 +21,33 @@ def __new__(cls, name, bases, attrs): for display ForeignKey fields. """ # https://bugs.python.org/issue29270 - attrs.pop('__classcell__', None) + attrs.pop("__classcell__", None) new_class = super().__new__(cls, name, bases, attrs) # Generate second class only for export which has added # additional *_str fields - export_class = super().__new__( - cls, '{}Exporter'.format(name), bases, attrs - ) + export_class = super().__new__(cls, "{}Exporter".format(name), bases, attrs) update_fields = [] for name, field in new_class.fields.items(): update_fields.append((name, field)) - field_name = '{}_str'.format(name) + field_name = "{}_str".format(name) field_params = dict( - column_name='{}_str'.format(field.column_name), + column_name="{}_str".format(field.column_name), attribute=field.attribute, - readonly=True + readonly=True, ) # skip str field if pointer implicitly - if getattr(field, '_skip_str_field', False): + if getattr(field, "_skip_str_field", False): continue elif isinstance(field.widget, widgets.ForeignKeyWidget): - field_params['widget'] = ExportForeignKeyStrWidget() + field_params["widget"] = ExportForeignKeyStrWidget() elif isinstance(field.widget, ManyToManyThroughWidget): - field_params['widget'] = ExportManyToManyStrTroughWidget( + field_params["widget"] = ExportManyToManyStrTroughWidget( model=field.widget.model, related_model=field.widget.related_model, through_field=field.widget.through_field, ) elif isinstance(field.widget, widgets.ManyToManyWidget): - field_params['widget'] = ExportManyToManyStrWidget( + field_params["widget"] = ExportManyToManyStrWidget( model=field.widget.model ) else: @@ -61,13 +59,11 @@ def __new__(cls, name, bases, attrs): # to `select_related` - usefull when it's need to be fetched # using `prefetch_related` (ex. for `parent` field with more # logic in fetching it) - '_exclude_in_select_related' + "_exclude_in_select_related" ]: if hasattr(field, extra_param_name): setattr( - new_field, - extra_param_name, - getattr(field, extra_param_name) + new_field, extra_param_name, getattr(field, extra_param_name) ) update_fields.append((field_name, new_field)) export_class.fields = OrderedDict(update_fields) @@ -76,33 +72,27 @@ def __new__(cls, name, bases, attrs): class ImportForeignKeyMixin(object): - """ImportForeignKeyMixin class for django import-export resources.""" def get_or_init_instance(self, instance_loader, row): - self.old_object_pk = row.get('id', None) - remove_id = getattr(settings, 'REMOVE_ID_FROM_IMPORT', False) + self.old_object_pk = row.get("id", None) + remove_id = getattr(settings, "REMOVE_ID_FROM_IMPORT", False) if remove_id: - row['id'] = None + row["id"] = None return super(ImportForeignKeyMixin, self).get_or_init_instance( instance_loader, row ) def after_save_instance( - self, - instance, - using_transactions: bool, - dry_run: bool, - *args, - **kwargs + self, instance, using_transactions: bool, dry_run: bool, *args, **kwargs ): if not dry_run and self.old_object_pk: content_type = ContentType.objects.get_for_model(self._meta.model) ImportedObjects.objects.update_or_create( content_type=content_type, old_object_pk=self.old_object_pk, - defaults={'object_pk': instance.pk} + defaults={"object_pk": instance.pk}, ) def import_field(self, field, obj, data, is_m2m=False): @@ -110,7 +100,7 @@ def import_field(self, field, obj, data, is_m2m=False): Calls :meth:`import_export.fields.Field.save` if ``Field.attribute`` and ``Field.column_name`` are found in ``data``. """ - if field.column_name == 'management_ip': + if field.column_name == "management_ip": field.save(obj, data, is_m2m=False) elif field.attribute and field.column_name in data: field.save(obj, data, is_m2m) diff --git a/src/ralph/data_importer/models.py b/src/ralph/data_importer/models.py index da41dd37b0..58ac545caa 100644 --- a/src/ralph/data_importer/models.py +++ b/src/ralph/data_importer/models.py @@ -11,27 +11,21 @@ class ImportedObjectDoesNotExist(Exception): class ImportedObjects(TimeStampMixin, models.Model): - """Django models for imported objects.""" content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_pk = models.IntegerField(db_index=True) old_object_pk = models.CharField(max_length=255, db_index=True) - old_ci_uid = models.CharField( - max_length=255, db_index=True, null=True, blank=True - ) - object = fields.GenericForeignKey('content_type', 'object_pk') + old_ci_uid = models.CharField(max_length=255, db_index=True, null=True, blank=True) + object = fields.GenericForeignKey("content_type", "object_pk") def __str__(self): - return "{} - {}".format( - self.content_type.app_label, - self.content_type.model - ) + return "{} - {}".format(self.content_type.app_label, self.content_type.model) class Meta: unique_together = [ - ('content_type', 'object_pk'), - ('content_type', 'old_object_pk') + ("content_type", "object_pk"), + ("content_type", "old_object_pk"), ] @classmethod @@ -42,7 +36,7 @@ def get_object_from_old_pk(cls, model, old_pk): try: imported_obj = cls.objects.get( old_object_pk=old_pk, - content_type=ContentType.objects.get_for_model(model) + content_type=ContentType.objects.get_for_model(model), ) except cls.DoesNotExist: raise ImportedObjectDoesNotExist() @@ -51,7 +45,7 @@ def get_object_from_old_pk(cls, model, old_pk): return model.objects.get(id=imported_obj.object_pk) except model.DoesNotExist: raise ImportedObjectDoesNotExist( - 'Target object does not exist (it was probably removed)' + "Target object does not exist (it was probably removed)" ) @classmethod @@ -69,7 +63,7 @@ def create(cls, obj, old_pk): return cls.objects.create( content_type=ContentType.objects.get_for_model(obj._meta.model), object_pk=obj.pk, - old_object_pk=old_pk + old_object_pk=old_pk, ) @classmethod @@ -86,7 +80,7 @@ def get_imported_id(cls, obj): try: imported_obj = cls.objects.get( object_pk=obj.pk, - content_type=ContentType.objects.get_for_model(obj._meta.model) + content_type=ContentType.objects.get_for_model(obj._meta.model), ) except cls.DoesNotExist: raise ImportedObjectDoesNotExist() diff --git a/src/ralph/data_importer/resources.py b/src/ralph/data_importer/resources.py index 4e9634fab7..40408a4e23 100644 --- a/src/ralph/data_importer/resources.py +++ b/src/ralph/data_importer/resources.py @@ -7,17 +7,10 @@ from ralph.accounts.models import Region from ralph.assets.models import assets, base, BaseObject, configuration -from ralph.back_office.models import ( - BackOfficeAsset, - OfficeInfrastructure, - Warehouse -) +from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse from ralph.data_center.models import hosts, physical from ralph.data_importer.fields import PriceField, ThroughField -from ralph.data_importer.mixins import ( - ImportForeignKeyMeta, - ImportForeignKeyMixin -) +from ralph.data_importer.mixins import ImportForeignKeyMeta, ImportForeignKeyMixin from ralph.data_importer.widgets import ( AssetServiceEnvWidget, AssetServiceUidWidget, @@ -30,7 +23,7 @@ PriceAmountWidget, PriceCurrencyWidget, UserManyToManyWidget, - UserWidget + UserWidget, ) from ralph.domains.models.domains import Domain, DomainContract from ralph.licences.models import ( @@ -38,33 +31,27 @@ Licence, LicenceType, LicenceUser, - Software + Software, ) from ralph.networks.models import networks from ralph.operations.models import Operation, OperationType from ralph.supports.models import BaseObjectsSupport, Support, SupportType RalphResourceMeta = type( - 'RalphResourceMeta', - ( - ImportForeignKeyMeta, - resources.ModelDeclarativeMetaclass, - resources.Resource - ), - {} + "RalphResourceMeta", + (ImportForeignKeyMeta, resources.ModelDeclarativeMetaclass, resources.Resource), + {}, ) class RalphModelResource( - ImportForeignKeyMixin, - resources.ModelResource, - metaclass=RalphResourceMeta + ImportForeignKeyMixin, resources.ModelResource, metaclass=RalphResourceMeta ): pass class ResourceWithPrice(resources.ModelResource): - price = PriceField(attribute='price', widget=PriceAmountWidget()) + price = PriceField(attribute="price", widget=PriceAmountWidget()) price_currency = fields.Field( attribute="price", readonly=True, widget=PriceCurrencyWidget() ) @@ -72,41 +59,41 @@ class ResourceWithPrice(resources.ModelResource): class AssetModelResource(RalphModelResource): manufacturer = fields.Field( - column_name='manufacturer', - attribute='manufacturer', + column_name="manufacturer", + attribute="manufacturer", widget=ImportedForeignKeyWidget(assets.Manufacturer), ) category = fields.Field( - column_name='category', - attribute='category', + column_name="category", + attribute="category", widget=ImportedForeignKeyWidget(assets.Category), ) assets_count = fields.Field( readonly=True, - column_name='assets_count', - attribute='assets_count', + column_name="assets_count", + attribute="assets_count", ) class Meta: model = assets.AssetModel def get_queryset(self): - return assets.AssetModel.objects.annotate(assets_count=Count('assets')) + return assets.AssetModel.objects.annotate(assets_count=Count("assets")) def dehydrate_assets_count(self, model): # check if model has `assets_count` attribute first (it's only included # when using annotated queryset above) return ( model.assets_count - if hasattr(model, 'assets_count') + if hasattr(model, "assets_count") else model.assets.count() ) class CategoryResource(RalphModelResource): parent = fields.Field( - column_name='parent', - attribute='parent', + column_name="parent", + attribute="parent", widget=ImportedForeignKeyWidget(assets.Category), ) @@ -116,57 +103,59 @@ class Meta: class BackOfficeAssetResource(ResourceWithPrice, RalphModelResource): parent = fields.Field( - column_name='parent', - attribute='parent', + column_name="parent", + attribute="parent", widget=ImportedForeignKeyWidget(assets.Asset), ) service_env = fields.Field( - column_name='service_env', - attribute='service_env', - widget=AssetServiceEnvWidget(assets.ServiceEnvironment, 'name'), + column_name="service_env", + attribute="service_env", + widget=AssetServiceEnvWidget(assets.ServiceEnvironment, "name"), ) model = fields.Field( - column_name='model', - attribute='model', + column_name="model", + attribute="model", widget=ImportedForeignKeyWidget(assets.AssetModel), ) user = fields.Field( - column_name='user', - attribute='user', + column_name="user", + attribute="user", widget=UserWidget(get_user_model()), ) owner = fields.Field( - column_name='owner', - attribute='owner', + column_name="owner", + attribute="owner", widget=UserWidget(get_user_model()), ) warehouse = fields.Field( - column_name='warehouse', - attribute='warehouse', + column_name="warehouse", + attribute="warehouse", widget=ImportedForeignKeyWidget(Warehouse), ) region = fields.Field( - column_name='region', - attribute='region', + column_name="region", + attribute="region", widget=ImportedForeignKeyWidget(Region), ) property_of = fields.Field( - column_name='property_of', - attribute='property_of', + column_name="property_of", + attribute="property_of", widget=ImportedForeignKeyWidget(assets.AssetHolder), ) budget_info = fields.Field( - column_name='budget_info', - attribute='budget_info', + column_name="budget_info", + attribute="budget_info", widget=ImportedForeignKeyWidget(assets.BudgetInfo), ) class Meta: model = BackOfficeAsset - prefetch_related = ( - 'tags', + prefetch_related = ("tags",) + exclude = ( + "content_type", + "asset_ptr", + "baseobject_ptr", ) - exclude = ('content_type', 'asset_ptr', 'baseobject_ptr',) def dehydrate_depreciation_rate(self, bo_asset): return str(bo_asset.depreciation_rate) @@ -174,8 +163,8 @@ def dehydrate_depreciation_rate(self, bo_asset): class ServerRoomResource(RalphModelResource): data_center = fields.Field( - column_name='data_center', - attribute='data_center', + column_name="data_center", + attribute="data_center", widget=ImportedForeignKeyWidget(physical.DataCenter), ) @@ -185,8 +174,8 @@ class Meta: class RackResource(RalphModelResource): server_room = fields.Field( - column_name='server_room', - attribute='server_room', + column_name="server_room", + attribute="server_room", widget=ImportedForeignKeyWidget(physical.ServerRoom), ) @@ -204,48 +193,48 @@ class DiscoveryDataCenterResource(RalphModelResource): Ralph3 stores all data centers in one table (physical.DataCenter), so this resource allows to import discovery data centers from Ralph2. """ + class Meta: model = physical.DataCenter class NetworkResource(RalphModelResource): data_center = fields.Field( - column_name='data_center', - attribute='data_center', + column_name="data_center", + attribute="data_center", widget=ImportedForeignKeyWidget(physical.DataCenter), ) network_environment = fields.Field( - column_name='network_environment', - attribute='network_environment', + column_name="network_environment", + attribute="network_environment", widget=ImportedForeignKeyWidget(networks.NetworkEnvironment), ) kind = fields.Field( - column_name='kind', - attribute='kind', + column_name="kind", + attribute="kind", widget=ImportedForeignKeyWidget(networks.NetworkKind), ) terminators = fields.Field( - column_name='terminators', - attribute='terminators', + column_name="terminators", + attribute="terminators", widget=BaseObjectManyToManyWidget(model=assets.BaseObject), ) class Meta: model = networks.Network - exclude = ('gateway_as_int', 'min_ip', 'max_ip') + exclude = ("gateway_as_int", "min_ip", "max_ip") class IPAddressResource(RalphModelResource): - base_object = fields.Field( - column_name='asset', - attribute='base_object', + column_name="asset", + attribute="base_object", widget=BaseObjectWidget(assets.BaseObject), ) network = fields.Field( - column_name='network', - attribute='network', + column_name="network", + attribute="network", widget=ImportedForeignKeyWidget(networks.Network), ) @@ -265,39 +254,39 @@ def skip_row(self, instance, original): class DataCenterAssetResource(ResourceWithPrice, RalphModelResource): parent = fields.Field( - column_name='parent', - attribute='parent', + column_name="parent", + attribute="parent", widget=ImportedForeignKeyWidget(physical.DataCenterAsset), ) parent._exclude_in_select_related = True parent_management_ip = fields.Field( readonly=True, - column_name='parent_management_ip', - attribute='parent_management_ip', + column_name="parent_management_ip", + attribute="parent_management_ip", ) service_env = fields.Field( - column_name='service_env', - attribute='service_env', - widget=AssetServiceEnvWidget(assets.ServiceEnvironment, 'name'), + column_name="service_env", + attribute="service_env", + widget=AssetServiceEnvWidget(assets.ServiceEnvironment, "name"), ) model = fields.Field( - column_name='model', - attribute='model', + column_name="model", + attribute="model", widget=ImportedForeignKeyWidget(assets.AssetModel), ) rack = fields.Field( - column_name='rack', - attribute='rack', + column_name="rack", + attribute="rack", widget=ImportedForeignKeyWidget(physical.Rack), ) budget_info = fields.Field( - column_name='budget_info', - attribute='budget_info', + column_name="budget_info", + attribute="budget_info", widget=ImportedForeignKeyWidget(assets.BudgetInfo), ) management_ip = fields.Field( - column_name='management_ip', - attribute='management_ip', + column_name="management_ip", + attribute="management_ip", widget=IPManagementWidget(model=networks.IPAddress), ) # no need for str field - management_ip will be exported as str @@ -306,18 +295,22 @@ class DataCenterAssetResource(ResourceWithPrice, RalphModelResource): class Meta: model = physical.DataCenterAsset select_related = ( - 'model__manufacturer', 'model__category', - 'service_env__service', 'service_env__environment', - 'rack__server_room__data_center', - 'configuration_path', - 'property_of', - 'parent', - 'budget_info', + "model__manufacturer", + "model__category", + "service_env__service", + "service_env__environment", + "rack__server_room__data_center", + "configuration_path", + "property_of", + "parent", + "budget_info", ) prefetch_related = ( - 'tags', 'ethernet_set__ipaddress', 'parent__ethernet_set__ipaddress', + "tags", + "ethernet_set__ipaddress", + "parent__ethernet_set__ipaddress", ) - exclude = ('content_type', 'asset_ptr', 'baseobject_ptr', 'connections') + exclude = ("content_type", "asset_ptr", "baseobject_ptr", "connections") def dehydrate_depreciation_rate(self, dc_asset): return str(dc_asset.depreciation_rate) @@ -338,7 +331,7 @@ def dehydrate_parent_str(self, dc_asset) -> str: try: return dc_asset.parent._str_with_type except AttributeError: - return '' + return "" def dehydrate_management_ip(self, dc_asset): return str(self._get_management_ip(dc_asset)) @@ -349,13 +342,13 @@ def dehydrate_parent_management_ip(self, dc_asset): class ConnectionResource(RalphModelResource): outbound = fields.Field( - column_name='outbound', - attribute='outbound', + column_name="outbound", + attribute="outbound", widget=ImportedForeignKeyWidget(physical.DataCenterAsset), ) inbound = fields.Field( - column_name='outbound', - attribute='outbound', + column_name="outbound", + attribute="outbound", widget=ImportedForeignKeyWidget(physical.DataCenterAsset), ) @@ -365,60 +358,63 @@ class Meta: class LicenceResource(ResourceWithPrice, RalphModelResource): manufacturer = fields.Field( - column_name='manufacturer', - attribute='manufacturer', + column_name="manufacturer", + attribute="manufacturer", widget=ImportedForeignKeyWidget(assets.Manufacturer), ) licence_type = fields.Field( - column_name='licence_type', - attribute='licence_type', + column_name="licence_type", + attribute="licence_type", widget=ImportedForeignKeyWidget(LicenceType), ) software = fields.Field( - column_name='software', - attribute='software', + column_name="software", + attribute="software", widget=ImportedForeignKeyWidget(Software), ) region = fields.Field( - column_name='region', - attribute='region', + column_name="region", + attribute="region", widget=ImportedForeignKeyWidget(Region), ) office_infrastructure = fields.Field( - column_name='office_infrastructure', - attribute='office_infrastructure', + column_name="office_infrastructure", + attribute="office_infrastructure", widget=ImportedForeignKeyWidget(OfficeInfrastructure), ) users = ThroughField( - column_name='users', - attribute='users', + column_name="users", + attribute="users", widget=UserManyToManyWidget(model=LicenceUser), through_model=LicenceUser, - through_from_field_name='licence', - through_to_field_name='user' + through_from_field_name="licence", + through_to_field_name="user", ) base_objects = ThroughField( - column_name='base_objects', - attribute='baseobjectlicence_set', + column_name="base_objects", + attribute="baseobjectlicence_set", widget=ManyToManyThroughWidget( model=BaseObjectLicence, related_model=base.BaseObject, - through_field='base_object' + through_field="base_object", ), through_model=BaseObjectLicence, - through_from_field_name='licence', - through_to_field_name='base_object' + through_from_field_name="licence", + through_to_field_name="base_object", ) service_uid = fields.Field( - column_name='service_uid', - attribute='service_env', + column_name="service_uid", + attribute="service_env", widget=AssetServiceUidWidget(assets.ServiceEnvironment), ) class Meta: model = Licence - prefetch_related = ('tags',) - exclude = ('content_type', 'baseobject_ptr', ) + prefetch_related = ("tags",) + exclude = ( + "content_type", + "baseobject_ptr", + ) def get_queryset(self): return Licence.objects_used_free_with_related.all() @@ -427,54 +423,56 @@ def get_queryset(self): class SupportTypeResource(RalphModelResource): - class Meta: model = SupportType class SupportResource(ResourceWithPrice, RalphModelResource): support_type = fields.Field( - column_name='support_type', - attribute='support_type', + column_name="support_type", + attribute="support_type", widget=ImportedForeignKeyWidget(SupportType), ) base_objects = ThroughField( - column_name='base_objects', - attribute='baseobjectssupport_set', + column_name="base_objects", + attribute="baseobjectssupport_set", widget=ManyToManyThroughWidget( model=BaseObjectsSupport, related_model=base.BaseObject, - through_field='baseobject' + through_field="baseobject", ), through_model=BaseObjectsSupport, - through_from_field_name='support', - through_to_field_name='baseobject' + through_from_field_name="support", + through_to_field_name="baseobject", ) region = fields.Field( - column_name='region', - attribute='region', + column_name="region", + attribute="region", widget=ImportedForeignKeyWidget(Region), ) budget_info = fields.Field( - column_name='budget_info', - attribute='budget_info', + column_name="budget_info", + attribute="budget_info", widget=ImportedForeignKeyWidget(assets.BudgetInfo), ) property_of = fields.Field( - column_name='property_of', - attribute='property_of', + column_name="property_of", + attribute="property_of", widget=ImportedForeignKeyWidget(assets.AssetHolder), ) assigned_objects_count = fields.Field( readonly=True, - column_name='assigned_objects_count', - attribute='assigned_objects_count', + column_name="assigned_objects_count", + attribute="assigned_objects_count", ) class Meta: model = Support - exclude = ('content_type', 'baseobject_ptr',) - prefetch_related = ('tags',) + exclude = ( + "content_type", + "baseobject_ptr", + ) + prefetch_related = ("tags",) def get_queryset(self): return Support.objects_with_related.all() @@ -490,8 +488,8 @@ def dehydrate_assigned_objects_count(self, support): class ProfitCenterResource(RalphModelResource): business_segment = fields.Field( - column_name='business_segment', - attribute='business_segment', + column_name="business_segment", + attribute="business_segment", widget=ImportedForeignKeyWidget(assets.BusinessSegment), ) @@ -501,27 +499,27 @@ class Meta: class ServiceResource(RalphModelResource): profit_center = fields.Field( - column_name='profit_center', - attribute='profit_center', + column_name="profit_center", + attribute="profit_center", widget=ImportedForeignKeyWidget(assets.ProfitCenter), ) business_owners = fields.Field( - column_name='business_owners', - attribute='business_owners', + column_name="business_owners", + attribute="business_owners", widget=UserManyToManyWidget(get_user_model()), ) technical_owners = fields.Field( - column_name='technical_owners', - attribute='technical_owners', + column_name="technical_owners", + attribute="technical_owners", widget=UserManyToManyWidget(get_user_model()), ) environments = ThroughField( - column_name='environments', - attribute='environments', + column_name="environments", + attribute="environments", widget=widgets.ManyToManyWidget(model=assets.Environment), through_model=assets.ServiceEnvironment, - through_from_field_name='service', - through_to_field_name='environment' + through_from_field_name="service", + through_to_field_name="environment", ) class Meta: @@ -530,13 +528,13 @@ class Meta: class ServiceEnvironmentResource(RalphModelResource): service = fields.Field( - column_name='service', - attribute='service', + column_name="service", + attribute="service", widget=ImportedForeignKeyWidget(assets.Service), ) environment = fields.Field( - column_name='environment', - attribute='environment', + column_name="environment", + attribute="environment", widget=ImportedForeignKeyWidget(assets.Environment), ) @@ -546,13 +544,13 @@ class Meta: class BaseObjectLicenceResource(RalphModelResource): licence = fields.Field( - column_name='licence', - attribute='licence', + column_name="licence", + attribute="licence", widget=ImportedForeignKeyWidget(Licence), ) base_object = fields.Field( - column_name='base_object', - attribute='base_object', + column_name="base_object", + attribute="base_object", widget=BaseObjectWidget(base.BaseObject), ) @@ -562,13 +560,13 @@ class Meta: class LicenceUserResource(RalphModelResource): licence = fields.Field( - column_name='licence', - attribute='licence', + column_name="licence", + attribute="licence", widget=ImportedForeignKeyWidget(Licence), ) user = fields.Field( - column_name='user', - attribute='user', + column_name="user", + attribute="user", widget=UserWidget(get_user_model()), ) @@ -578,13 +576,13 @@ class Meta: class BaseObjectsSupportResource(RalphModelResource): support = fields.Field( - column_name='support', - attribute='support', + column_name="support", + attribute="support", widget=ImportedForeignKeyWidget(Support), ) baseobject = fields.Field( - column_name='baseobject', - attribute='baseobject', + column_name="baseobject", + attribute="baseobject", widget=BaseObjectWidget(base.BaseObject), ) @@ -594,56 +592,59 @@ class Meta: class BaseObjectsSupportRichResource(RalphModelResource): price_per_object = fields.Field( - column_name='support__price_per_object', + column_name="support__price_per_object", ) class Meta: model = BaseObjectsSupport fields = ( - 'support__contract_id', - 'support__support_type', - 'support__serial_no', - 'support__name', - 'support__price', - 'price_per_object', - 'support__date_from', - 'support__date_to', - 'support__description', - 'support__invoice_no', - 'support__invoice_date', - 'support__property_of', - 'support__budget_info', - 'baseobject__asset__hostname', - 'baseobject__asset__barcode', - 'baseobject__asset__sn', - 'baseobject__asset__model', - 'baseobject__service_env', - 'baseobject__configuration_path', + "support__contract_id", + "support__support_type", + "support__serial_no", + "support__name", + "support__price", + "price_per_object", + "support__date_from", + "support__date_to", + "support__description", + "support__invoice_no", + "support__invoice_date", + "support__property_of", + "support__budget_info", + "baseobject__asset__hostname", + "baseobject__asset__barcode", + "baseobject__asset__sn", + "baseobject__asset__model", + "baseobject__service_env", + "baseobject__configuration_path", ) - def get_queryset(self): - return super().get_queryset().annotate( - objects_count=Count('support__baseobjectssupport') - ) + # def get_queryset(self): + # return ( + # super() + # .get_queryset() + # .annotate(objects_count=Count("support__baseobjectssupport")) + # ) def dehydrate_price_per_object(self, bo_support): support = bo_support.support - price = getattr(support.price, 'amount', Decimal('0.00')) + price = getattr(support.price, "amount", Decimal("0.00")) return str( round(price / bo_support.objects_count, 2) - if bo_support.objects_count > 0 else Decimal('0.00') + if bo_support.objects_count > 0 + else Decimal("0.00") ) class RackAccessoryResource(RalphModelResource): accessory = fields.Field( - column_name='accessory', - attribute='accessory', + column_name="accessory", + attribute="accessory", widget=ImportedForeignKeyWidget(physical.Accessory), ) rack = fields.Field( - column_name='rack', - attribute='rack', + column_name="rack", + attribute="rack", widget=ImportedForeignKeyWidget(physical.Rack), ) @@ -653,8 +654,8 @@ class Meta: class RegionResource(RalphModelResource): users = fields.Field( - column_name='users', - attribute='users', + column_name="users", + attribute="users", widget=UserManyToManyWidget(get_user_model()), ) @@ -663,28 +664,25 @@ class Meta: class AssetHolderResource(RalphModelResource): - class Meta: model = assets.AssetHolder class OfficeInfrastructureResource(RalphModelResource): - class Meta: model = OfficeInfrastructure class BudgetInfoResource(RalphModelResource): - class Meta: model = assets.BudgetInfo class DomainContractResource(ResourceWithPrice, RalphModelResource): domain = fields.Field( - column_name='domain', - attribute='domain', - widget=widgets.ForeignKeyWidget(Domain, 'name'), + column_name="domain", + attribute="domain", + widget=widgets.ForeignKeyWidget(Domain, "name"), ) class Meta: @@ -693,42 +691,43 @@ class Meta: class DomainResource(RalphModelResource): business_segment = fields.Field( - column_name='business_segment', - attribute='business_segment', + column_name="business_segment", + attribute="business_segment", widget=widgets.ForeignKeyWidget( - assets.BusinessSegment, 'name', + assets.BusinessSegment, + "name", ), ) business_owner = fields.Field( - column_name='business_owner', - attribute='business_owner', + column_name="business_owner", + attribute="business_owner", widget=UserWidget(get_user_model()), ) technical_owner = fields.Field( - column_name='technical_owner', - attribute='technical_owner', + column_name="technical_owner", + attribute="technical_owner", widget=UserWidget(get_user_model()), ) domain_holder = fields.Field( - column_name='domain_holder', - attribute='domain_holder', + column_name="domain_holder", + attribute="domain_holder", widget=widgets.ForeignKeyWidget(assets.AssetHolder), ) service_env = fields.Field( - column_name='service_env', - attribute='service_env', + column_name="service_env", + attribute="service_env", widget=AssetServiceEnvWidget(assets.ServiceEnvironment), ) class Meta: model = Domain - exclude = ('baseobject_ptr',) + exclude = ("baseobject_ptr",) class OperationTypeResource(RalphModelResource): parent = fields.Field( - column_name='parent', - attribute='parent', + column_name="parent", + attribute="parent", widget=ImportedForeignKeyWidget(OperationType), ) @@ -738,62 +737,59 @@ class Meta: class OperationResource(RalphModelResource): type = fields.Field( - column_name='type', - attribute='type', + column_name="type", + attribute="type", widget=ImportedForeignKeyWidget(OperationType), ) base_objects = fields.Field( - column_name='base_objects', - attribute='base_objects', + column_name="base_objects", + attribute="base_objects", widget=widgets.ManyToManyWidget(model=base.BaseObject), default=[], ) assignee = fields.Field( - column_name='assignee', - attribute='assignee', + column_name="assignee", + attribute="assignee", widget=UserWidget(get_user_model()), ) reporter = fields.Field( - column_name='reporter', - attribute='reporter', + column_name="reporter", + attribute="reporter", widget=UserWidget(get_user_model()), ) service_name = fields.Field( - column_name='base_objects_service_names', - attribute='base_objects', + column_name="base_objects_service_names", + attribute="base_objects", widget=BaseObjectServiceNamesM2MWidget(model=base.BaseObject), default=[], - readonly=True + readonly=True, ) service_name._skip_str_field = True class Meta: - select_related = ( - 'assignee', 'reporter', 'type', 'status' - ) + select_related = ("assignee", "reporter", "type", "status") prefetch_related = ( - 'tags', + "tags", Prefetch( - lookup='base_objects', + lookup="base_objects", queryset=BaseObject.polymorphic_objects.polymorphic_filter( operations__in=Operation.objects.all() - ).select_related( - 'service_env', - 'service_env__service', - 'service_env__environment' - ).polymorphic_select_related( - Cluster=['type'], - ServiceEnvironment=['service', 'environment'] ) - ) + .select_related( + "service_env", "service_env__service", "service_env__environment" + ) + .polymorphic_select_related( + Cluster=["type"], ServiceEnvironment=["service", "environment"] + ), + ), ) model = Operation class ConfigurationModuleResource(RalphModelResource): parent = fields.Field( - column_name='parent', - attribute='parent', + column_name="parent", + attribute="parent", widget=ImportedForeignKeyWidget(configuration.ConfigurationModule), ) @@ -803,8 +799,8 @@ class Meta: class ConfigurationClassResource(RalphModelResource): module = fields.Field( - column_name='module', - attribute='module', + column_name="module", + attribute="module", widget=ImportedForeignKeyWidget(configuration.ConfigurationModule), ) @@ -815,20 +811,20 @@ class Meta: class DCHostResource(RalphModelResource): hostname = fields.Field( readonly=True, - column_name='hostname', - attribute='hostname', + column_name="hostname", + attribute="hostname", ) service_env = fields.Field( - column_name='service_env', - attribute='service_env', - widget=AssetServiceEnvWidget(assets.ServiceEnvironment, 'name'), + column_name="service_env", + attribute="service_env", + widget=AssetServiceEnvWidget(assets.ServiceEnvironment, "name"), ) ips = fields.Field( - column_name='ip_addresses', - attribute='ipaddresses', + column_name="ip_addresses", + attribute="ipaddresses", widget=widgets.ManyToManyWidget(model=networks.IPAddress), ) class Meta: model = hosts.DCHost - exclude = ('parent',) + exclude = ("parent",) diff --git a/src/ralph/data_importer/tests/test_commands.py b/src/ralph/data_importer/tests/test_commands.py index ce532cd833..4485a84e67 100644 --- a/src/ralph/data_importer/tests/test_commands.py +++ b/src/ralph/data_importer/tests/test_commands.py @@ -15,7 +15,7 @@ Environment, Manufacturer, Service, - ServiceEnvironment + ServiceEnvironment, ) from ralph.assets.models.choices import ObjectModelType from ralph.back_office.models import BackOfficeAsset, Warehouse @@ -26,15 +26,11 @@ from ralph.data_importer.management.commands.create_server_model import ( DEFAULT_MODEL_CATEGORY, DEFAULT_MODEL_MANUFACTURER, - DEFAULT_MODEL_NAME + DEFAULT_MODEL_NAME, ) from ralph.data_importer.models import ImportedObjects from ralph.data_importer.resources import AssetModelResource -from ralph.deployment.models import ( - Preboot, - PrebootConfiguration, - PrebootItemType -) +from ralph.deployment.models import Preboot, PrebootConfiguration, PrebootItemType from ralph.dhcp.models import DNSServerGroup from ralph.lib.transitions.conf import DEFAULT_ASYNC_TRANSITION_SERVICE_NAME from ralph.lib.transitions.models import Transition, TransitionModel @@ -45,9 +41,7 @@ class DataImporterTestCase(TestCase): """TestCase data importer command.""" def setUp(self): # noqa - self.base_dir = os.path.dirname( - os.path.dirname(os.path.abspath(__file__)) - ) + self.base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) asset_model = AssetModel() asset_model.name = "asset_model_1" @@ -55,9 +49,7 @@ def setUp(self): # noqa asset_model.save() asset_content_type = ContentType.objects.get_for_model(AssetModel) ImportedObjects.objects.create( - content_type=asset_content_type, - object_pk=asset_model.pk, - old_object_pk=1 + content_type=asset_content_type, object_pk=asset_model.pk, old_object_pk=1 ) warehouse = Warehouse() @@ -66,9 +58,7 @@ def setUp(self): # noqa warehouse_content_type = ContentType.objects.get_for_model(Warehouse) ImportedObjects.objects.create( - content_type=warehouse_content_type, - object_pk=warehouse.pk, - old_object_pk=1 + content_type=warehouse_content_type, object_pk=warehouse.pk, old_object_pk=1 ) environment = Environment() @@ -84,136 +74,105 @@ def setUp(self): # noqa service_environment.service = service service_environment.save() - region = Region(name='region_1') + region = Region(name="region_1") region.save() region_content_type = ContentType.objects.get_for_model(region) ImportedObjects.objects.create( - content_type=region_content_type, - object_pk=region.pk, - old_object_pk=1 + content_type=region_content_type, object_pk=region.pk, old_object_pk=1 ) user_model = get_user_model() - for user in ('iron.man', 'superman', 'james.bond', 'sherlock.holmes'): + for user in ("iron.man", "superman", "james.bond", "sherlock.holmes"): user_model.objects.create(username=user) def test_get_resource(self): """Test get resources method.""" - asset_model_resource = importer.get_resource('AssetModel') + asset_model_resource = importer.get_resource("AssetModel") self.assertIsInstance(asset_model_resource, AssetModelResource) def test_importer_command_warehouse(self): """Test importer management command with Warehouse model.""" - warehouse_csv = os.path.join( - self.base_dir, - 'tests/samples/warehouses.csv' - ) + warehouse_csv = os.path.join(self.base_dir, "tests/samples/warehouses.csv") management.call_command( - 'importer', + "importer", warehouse_csv, - type='file', - model_name='Warehouse', - map_imported_id_to_new_id=True + type="file", + model_name="Warehouse", + map_imported_id_to_new_id=True, ) - self.assertTrue(Warehouse.objects.filter( - name="PoznaÅ„" - ).exists()) + self.assertTrue(Warehouse.objects.filter(name="PoznaÅ„").exists()) def test_importer_command_back_office_asset(self): """Test importer management command with BackOfficeAsset model.""" back_office_csv = os.path.join( - self.base_dir, - 'tests/samples/back_office_assets.csv' + self.base_dir, "tests/samples/back_office_assets.csv" ) management.call_command( - 'importer', + "importer", back_office_csv, - type='file', - model_name='BackOfficeAsset', - map_imported_id_to_new_id=True + type="file", + model_name="BackOfficeAsset", + map_imported_id_to_new_id=True, ) - self.assertTrue(BackOfficeAsset.objects.filter( - sn="bo_asset_sn" - ).exists()) + self.assertTrue(BackOfficeAsset.objects.filter(sn="bo_asset_sn").exists()) back_office_asset = BackOfficeAsset.objects.get(sn="bo_asset_sn") - self.assertEqual( - back_office_asset.warehouse.name, - "warehouse_1" - ) - self.assertEqual( - back_office_asset.model.name, - "asset_model_1" - ) - self.assertEqual( - back_office_asset.service_env.service.name, - "service_1" - ) + self.assertEqual(back_office_asset.warehouse.name, "warehouse_1") + self.assertEqual(back_office_asset.model.name, "asset_model_1") + self.assertEqual(back_office_asset.service_env.service.name, "service_1") def test_importer_command_regions(self): """Test importer management command with BackOfficeAsset model.""" old_regions_count = Region.objects.count() - regions_csv = os.path.join( - self.base_dir, - 'tests/samples/regions.csv' - ) + regions_csv = os.path.join(self.base_dir, "tests/samples/regions.csv") management.call_command( - 'importer', + "importer", regions_csv, - type='file', - model_name='Region', - map_imported_id_to_new_id=True + type="file", + model_name="Region", + map_imported_id_to_new_id=True, ) self.assertEqual(Region.objects.count(), old_regions_count + 2) - region_1 = Region.objects.get(name='USA') - for user in ('iron.man', 'superman'): - self.assertIn( - user, region_1.users.values_list('username', flat=True) - ) + region_1 = Region.objects.get(name="USA") + for user in ("iron.man", "superman"): + self.assertIn(user, region_1.users.values_list("username", flat=True)) def test_importer_command_with_tab(self): """Test importer management command with Warehouse model and tab separation file """ - warehouse_csv = os.path.join( - self.base_dir, - 'tests/samples/warehouses_tab.csv' - ) + warehouse_csv = os.path.join(self.base_dir, "tests/samples/warehouses_tab.csv") management.call_command( - 'importer', + "importer", warehouse_csv, - type='file', - model_name='Warehouse', - delimiter='\t', - map_imported_id_to_new_id=True + type="file", + model_name="Warehouse", + delimiter="\t", + map_imported_id_to_new_id=True, ) - self.assertTrue(Warehouse.objects.filter( - name="Barcelona" - ).exists()) + self.assertTrue(Warehouse.objects.filter(name="Barcelona").exists()) def test_importer_command_with_skipid(self): """Test importer management command with Warehouse model and tab separation file """ warehouse_csv = os.path.join( - self.base_dir, - 'tests/samples/warehouses_skipid.csv' + self.base_dir, "tests/samples/warehouses_skipid.csv" ) management.call_command( - 'importer', + "importer", warehouse_csv, - '--skipid', - type='file', - model_name='Warehouse', - delimiter=',', - map_imported_id_to_new_id=True + "--skipid", + type="file", + model_name="Warehouse", + delimiter=",", + map_imported_id_to_new_id=True, ) warehouse = Warehouse.objects.filter(name="Cupertino").first() self.assertNotEqual(warehouse.pk, 200) warehouse_content_type = ContentType.objects.get_for_model(Warehouse) warehouse_exists = ImportedObjects.objects.filter( - content_type=warehouse_content_type, - old_object_pk=200 + content_type=warehouse_content_type, old_object_pk=200 ).exists() self.assertTrue(warehouse_exists) @@ -222,198 +181,142 @@ def test_importer_command_with_semicolon(self): semicolon separation file """ warehouse_csv = os.path.join( - self.base_dir, - 'tests/samples/warehouses_semicolon.csv' + self.base_dir, "tests/samples/warehouses_semicolon.csv" ) management.call_command( - 'importer', + "importer", warehouse_csv, - type='file', - model_name='Warehouse', - delimiter=';', - map_imported_id_to_new_id=True + type="file", + model_name="Warehouse", + delimiter=";", + map_imported_id_to_new_id=True, ) - self.assertTrue(Warehouse.objects.filter( - name="Berlin" - ).exists()) + self.assertTrue(Warehouse.objects.filter(name="Berlin").exists()) def test_imported_object(self): """Test importer management command with ImportedObjects model.""" - data_center = DataCenterFactory(name='CSV_test') - data_center_content_type = ContentType.objects.get_for_model( - DataCenter - ) + data_center = DataCenterFactory(name="CSV_test") + data_center_content_type = ContentType.objects.get_for_model(DataCenter) ImportedObjects.objects.create( content_type=data_center_content_type, object_pk=data_center.pk, - old_object_pk=1 - ) - server_room_csv = os.path.join( - self.base_dir, - 'tests/samples/server_room.csv' - ) - rack_csv = os.path.join( - self.base_dir, - 'tests/samples/rack.csv' + old_object_pk=1, ) + server_room_csv = os.path.join(self.base_dir, "tests/samples/server_room.csv") + rack_csv = os.path.join(self.base_dir, "tests/samples/rack.csv") management.call_command( - 'importer', + "importer", server_room_csv, - type='file', - model_name='ServerRoom', - delimiter=',', - map_imported_id_to_new_id=True + type="file", + model_name="ServerRoom", + delimiter=",", + map_imported_id_to_new_id=True, ) content_type = ContentType.objects.get_for_model(ServerRoom) imported_object_exists = ImportedObjects.objects.filter( - content_type=content_type, - old_object_pk=1 + content_type=content_type, old_object_pk=1 ).exists() self.assertTrue(imported_object_exists) management.call_command( - 'importer', + "importer", rack_csv, - type='file', - model_name='Rack', - delimiter=',', - map_imported_id_to_new_id=True + type="file", + model_name="Rack", + delimiter=",", + map_imported_id_to_new_id=True, ) - self.assertTrue(Rack.objects.filter( - name="Rack_csv_test" - ).exists()) + self.assertTrue(Rack.objects.filter(name="Rack_csv_test").exists()) def test_from_dir_command(self): - warehouse_dir = os.path.join( - self.base_dir, - 'tests/samples/warehouses' - ) + warehouse_dir = os.path.join(self.base_dir, "tests/samples/warehouses") management.call_command( - 'importer', - warehouse_dir, - type='dir', - map_imported_id_to_new_id=True + "importer", warehouse_dir, type="dir", map_imported_id_to_new_id=True ) - self.assertTrue(Warehouse.objects.filter( - name="From dir Warszawa" - ).exists()) - self.assertTrue(Warehouse.objects.filter( - name="From dir London" - ).exists()) + self.assertTrue(Warehouse.objects.filter(name="From dir Warszawa").exists()) + self.assertTrue(Warehouse.objects.filter(name="From dir London").exists()) def test_from_zipfile_command(self): - warehouse_zip = os.path.join( - self.base_dir, - 'tests/samples/warehouses.zip' - ) + warehouse_zip = os.path.join(self.base_dir, "tests/samples/warehouses.zip") management.call_command( - 'importer', - warehouse_zip, - type='zip', - map_imported_id_to_new_id=True + "importer", warehouse_zip, type="zip", map_imported_id_to_new_id=True ) - self.assertTrue(Warehouse.objects.filter( - name="From zip Warszawa" - ).exists()) + self.assertTrue(Warehouse.objects.filter(name="From zip Warszawa").exists()) - self.assertTrue(Warehouse.objects.filter( - name="From zip London" - ).exists()) + self.assertTrue(Warehouse.objects.filter(name="From zip London").exists()) class IPManagementTestCase(TestCase): def setUp(self): - self.base_dir = os.path.dirname( - os.path.dirname(os.path.abspath(__file__)) - ) + self.base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) asset_model = AssetModel() asset_model.id = 1 # required by csvs file asset_model.name = "asset_model_1" asset_model.type = ObjectModelType.all asset_model.save() - def test_data_center_asset_is_imported_when_ip_management_is_created( - self - ): + def test_data_center_asset_is_imported_when_ip_management_is_created(self): xlsx_path = os.path.join( - self.base_dir, - 'tests/samples/management_ip_existing.csv' - ) - self.assertFalse( - IPAddress.objects.filter(address='10.0.0.103').exists() + self.base_dir, "tests/samples/management_ip_existing.csv" ) + self.assertFalse(IPAddress.objects.filter(address="10.0.0.103").exists()) management.call_command( - 'importer', + "importer", xlsx_path, - type='file', - model_name='DataCenterAsset', + type="file", + model_name="DataCenterAsset", map_imported_id_to_new_id=False, ) - self.assertTrue( - DataCenterAsset.objects.get(hostname='EMC1-3') - ) + self.assertTrue(DataCenterAsset.objects.get(hostname="EMC1-3")) self.assertTrue( DataCenterAsset.objects.get().ethernet_set.get().ipaddress.address, - '10.0.0.103' + "10.0.0.103", ) - def test_data_center_asset_is_imported_when_ip_management_is_reused( - self - ): - IPAddress.objects.create(address='10.0.0.103') - self.assertTrue( - IPAddress.objects.filter(address='10.0.0.103').exists() - ) + def test_data_center_asset_is_imported_when_ip_management_is_reused(self): + IPAddress.objects.create(address="10.0.0.103") + self.assertTrue(IPAddress.objects.filter(address="10.0.0.103").exists()) xlsx_path = os.path.join( - self.base_dir, - 'tests/samples/management_ip_existing.csv' + self.base_dir, "tests/samples/management_ip_existing.csv" ) management.call_command( - 'importer', + "importer", xlsx_path, - type='file', - model_name='DataCenterAsset', + type="file", + model_name="DataCenterAsset", map_imported_id_to_new_id=False, ) - self.assertTrue( - DataCenterAsset.objects.get(hostname='EMC1-3') - ) + self.assertTrue(DataCenterAsset.objects.get(hostname="EMC1-3")) self.assertTrue( DataCenterAsset.objects.get().ethernet_set.get().ipaddress.address, - '10.0.0.103' + "10.0.0.103", ) - def test_data_center_asset_is_imported_when_ip_management_is_blank( - self - ): - xlsx_path = os.path.join( - self.base_dir, 'tests/samples/management_ip_blank.csv' - ) + def test_data_center_asset_is_imported_when_ip_management_is_blank(self): + xlsx_path = os.path.join(self.base_dir, "tests/samples/management_ip_blank.csv") management.call_command( - 'importer', + "importer", xlsx_path, - type='file', - model_name='DataCenterAsset', + type="file", + model_name="DataCenterAsset", map_imported_id_to_new_id=False, ) - self.assertTrue( - DataCenterAsset.objects.get(hostname='EMC1-3') - ) + self.assertTrue(DataCenterAsset.objects.get(hostname="EMC1-3")) @ddt class TestCreateTransitionsCommand(TestCase): @classmethod def setUpTestData(cls): - management.call_command('create_transitions') + management.call_command("create_transitions") def test_transitions_generated(self): transitions = Transition.objects.all() @@ -422,64 +325,59 @@ def test_transitions_generated(self): @unpack @data( ( - 'Deploy', + "Deploy", [ DataCenterAssetStatus.new.id, DataCenterAssetStatus.used.id, DataCenterAssetStatus.free.id, DataCenterAssetStatus.damaged.id, DataCenterAssetStatus.liquidated.id, - DataCenterAssetStatus.to_deploy.id + DataCenterAssetStatus.to_deploy.id, ], [ - 'assign_configuration_path', - 'assign_new_hostname', - 'assign_service_env', - 'clean_dhcp', - 'clean_hostname', - 'clean_ipaddresses', - 'cleanup_security_scans', - 'create_dhcp_entries', - 'create_dns_entries', - 'deploy', - 'wait_for_dhcp_servers', - 'wait_for_ping' + "assign_configuration_path", + "assign_new_hostname", + "assign_service_env", + "clean_dhcp", + "clean_hostname", + "clean_ipaddresses", + "cleanup_security_scans", + "create_dhcp_entries", + "create_dns_entries", + "deploy", + "wait_for_dhcp_servers", + "wait_for_ping", ], DEFAULT_ASYNC_TRANSITION_SERVICE_NAME, - 0 + 0, ), ( - 'Change config path', + "Change config path", [ DataCenterAssetStatus.new.id, DataCenterAssetStatus.used.id, DataCenterAssetStatus.free.id, DataCenterAssetStatus.damaged.id, DataCenterAssetStatus.liquidated.id, - DataCenterAssetStatus.to_deploy.id - ], - [ - 'assign_configuration_path' + DataCenterAssetStatus.to_deploy.id, ], + ["assign_configuration_path"], None, - 0 + 0, ), ( - 'Reinstall', + "Reinstall", [ DataCenterAssetStatus.new.id, DataCenterAssetStatus.used.id, DataCenterAssetStatus.free.id, DataCenterAssetStatus.damaged.id, DataCenterAssetStatus.liquidated.id, - DataCenterAssetStatus.to_deploy.id - ], - [ - 'deploy', - 'wait_for_ping' + DataCenterAssetStatus.to_deploy.id, ], + ["deploy", "wait_for_ping"], DEFAULT_ASYNC_TRANSITION_SERVICE_NAME, - 0 + 0, ), ) def test_transition_of_each_type_generated( @@ -489,27 +387,24 @@ def test_transition_of_each_type_generated( try: transition = Transition.objects.get( - model=TransitionModel.objects.get( - content_type=content_type - ), + model=TransitionModel.objects.get(content_type=content_type), name=name, source=source, async_service_name=async_service_name, - target=target + target=target, ) except Transition.DoesNotExist as e: self.fail(e) self.assertCountEqual( - actions, - [action.name for action in transition.actions.all()] + actions, [action.name for action in transition.actions.all()] ) class TestCreateNetworkCommand(TestCase): @classmethod def setUpTestData(cls): - management.call_command('create_network', create_rack=True) + management.call_command("create_network", create_rack=True) def test_network_generated(self): networks = Network.objects.all() @@ -517,24 +412,23 @@ def test_network_generated(self): def test_network_addressing_generated(self): try: - network = Network.objects.get(name='10.0.0.0/24') + network = Network.objects.get(name="10.0.0.0/24") except Network.DoesNotExist: self.fail("Expected network not created.") - expected_gateway = '10.0.0.1' - expected_dns = ['10.0.0.11', '10.0.0.12'] - expected_dc = 'dc1' + expected_gateway = "10.0.0.1" + expected_dns = ["10.0.0.11", "10.0.0.12"] + expected_dc = "dc1" - self.assertEqual(ipaddress.ip_network('10.0.0.0/24'), network.address) + self.assertEqual(ipaddress.ip_network("10.0.0.0/24"), network.address) self.assertEqual(expected_gateway, str(network.gateway)) self.assertEqual(expected_dc, network.data_center.name) self.assertCountEqual( expected_dns, [ str(server.ip_address) - for server in - network.dns_servers_group.servers.all() - ] + for server in network.dns_servers_group.servers.all() + ], ) def test_dns_group_generated(self): @@ -554,9 +448,7 @@ def test_racks_created(self): class TestCreateServerModelCommand(TestCase): @classmethod def setUpTestData(cls): - management.call_command( - 'create_server_model', model_is_blade_server=True - ) + management.call_command("create_server_model", model_is_blade_server=True) def test_server_model_generated(self): models = AssetModel.objects.all() @@ -573,16 +465,12 @@ def test_server_model_generated(self): class TestCreatePrebootCommand(TestCase): @classmethod def setUpTestData(cls): - base_dir = os.path.dirname( - os.path.dirname(__file__) - ) - samples_dir = os.path.join( - base_dir, 'tests', 'samples' - ) + base_dir = os.path.dirname(os.path.dirname(__file__)) + samples_dir = os.path.join(base_dir, "tests", "samples") management.call_command( - 'create_preboot_configuration', - kickstart_file=os.path.join(samples_dir, 'kickstart_file'), - ipxe_file=os.path.join(samples_dir, 'ipxe_file') + "create_preboot_configuration", + kickstart_file=os.path.join(samples_dir, "kickstart_file"), + ipxe_file=os.path.join(samples_dir, "ipxe_file"), ) def test_preboot_details(self): @@ -590,21 +478,16 @@ def test_preboot_details(self): kickstart = PrebootConfiguration.objects.filter( type=PrebootItemType.kickstart.id ).first() - ipxe = PrebootConfiguration.objects.filter( - type=PrebootItemType.ipxe.id - ).first() + ipxe = PrebootConfiguration.objects.filter(type=PrebootItemType.ipxe.id).first() self.assertIn(kickstart, preboot.items.all()) self.assertIn(ipxe, preboot.items.all()) self.assertEqual("Preboot", preboot.name) - self.assertEqual( - "Automatically generated preboot.", - preboot.description - ) + self.assertEqual("Automatically generated preboot.", preboot.description) @unpack @data( (PrebootItemType.kickstart.id, "lang en_US\n"), - (PrebootItemType.ipxe.id, "#!ipxe\n") + (PrebootItemType.ipxe.id, "#!ipxe\n"), ) def test_preboot_items_configuration(self, item_type, item_configuration): item = PrebootConfiguration.objects.filter(type=item_type).first() @@ -613,7 +496,7 @@ def test_preboot_items_configuration(self, item_type, item_configuration): @unpack @data( (PrebootItemType.kickstart.id, "Preboot kickstart"), - (PrebootItemType.ipxe.id, "Preboot ipxe") + (PrebootItemType.ipxe.id, "Preboot ipxe"), ) def test_preboot_items_names(self, item_type, item_name): item = PrebootConfiguration.objects.filter(type=item_type).first() @@ -624,7 +507,7 @@ def test_preboot_items_names(self, item_type, item_name): class TestInitialDataCommand(TestCase): @classmethod def setUpTestData(cls): - management.call_command('initial_data') + management.call_command("initial_data") def test_networks_generated(self): networks = Network.objects.all() @@ -632,10 +515,10 @@ def test_networks_generated(self): @unpack @data( - ('10.0.0.0/16', '10.0.0.1', '10.0.0.11', '10.0.0.12'), - ('10.0.0.0/24', '10.0.0.1', '10.0.0.11', '10.0.0.12'), - ('10.0.1.0/24', '10.0.1.1', '10.0.0.11', '10.0.0.12'), - ('10.0.2.0/24', '10.0.2.1', '10.0.0.11', '10.0.0.12'), + ("10.0.0.0/16", "10.0.0.1", "10.0.0.11", "10.0.0.12"), + ("10.0.0.0/24", "10.0.0.1", "10.0.0.11", "10.0.0.12"), + ("10.0.1.0/24", "10.0.1.1", "10.0.0.11", "10.0.0.12"), + ("10.0.2.0/24", "10.0.2.1", "10.0.0.11", "10.0.0.12"), ) def test_subnets_generated( self, network_address, gateway_address, dns1_address, dns2_address @@ -643,37 +526,30 @@ def test_subnets_generated( try: network = Network.objects.get(name=network_address) except Network.DoesNotExist: - self.fail( - "Expected subnet {} not created.".format(network_address) - ) + self.fail("Expected subnet {} not created.".format(network_address)) expected_dns = [dns1_address, dns2_address] - self.assertEqual( - ipaddress.ip_network(network_address), network.address - ) + self.assertEqual(ipaddress.ip_network(network_address), network.address) self.assertEqual(gateway_address, str(network.gateway)) self.assertCountEqual( expected_dns, [ str(server.ip_address) - for server in - network.dns_servers_group.servers.all() - ] + for server in network.dns_servers_group.servers.all() + ], ) def test_user_created(self): try: user_model = get_user_model() - user_model.objects.get(username='admin') + user_model.objects.get(username="admin") except user_model.DoesNotExist: - self.fail( - "Admin user not created." - ) + self.fail("Admin user not created.") def test_configuration_path_created(self): try: - ConfigurationClass.objects.get(path='configuration_module/default') + ConfigurationClass.objects.get(path="configuration_module/default") except ConfigurationClass.DoesNotExist: self.fail("Default configuration path not created.") @@ -684,9 +560,7 @@ def test_asset_models_created(self): AssetModel.objects.get(name="Model {}".format(name)) except AssetModel.DoesNotExist: self.fail( - 'Asset model with name "Model {}" does not exist.'.format( - name - ) + 'Asset model with name "Model {}" does not exist.'.format(name) ) for name in ["A", "B", "C"]: try: diff --git a/src/ralph/data_importer/tests/test_demo_data.py b/src/ralph/data_importer/tests/test_demo_data.py index 584b14e4af..c6af27dfd9 100644 --- a/src/ralph/data_importer/tests/test_demo_data.py +++ b/src/ralph/data_importer/tests/test_demo_data.py @@ -7,9 +7,8 @@ class DemoDataTestCase(TestCase): - def test_demo_data_command(self): - management.call_command('demodata') + management.call_command("demodata") self.assertEqual(DataCenterAsset.objects.count(), 422) self.assertEqual(BackOfficeAsset.objects.count(), 280) self.assertTrue(get_user_model().objects.count() in range(32, 35)) diff --git a/src/ralph/data_importer/tests/test_export.py b/src/ralph/data_importer/tests/test_export.py index 814c903ace..e9ee478985 100644 --- a/src/ralph/data_importer/tests/test_export.py +++ b/src/ralph/data_importer/tests/test_export.py @@ -15,14 +15,14 @@ BackOfficeAssetLicenceFactory, DataCenterAssetLicenceFactory, LicenceFactory, - LicenceUserFactory + LicenceUserFactory, ) from ralph.supports.models import BaseObjectsSupport, Support from ralph.supports.tests.factories import ( BackOfficeAssetSupportFactory, BaseObjectsSupportFactory, DataCenterAssetSupportFactory, - SupportFactory + SupportFactory, ) @@ -41,16 +41,20 @@ def _export(self, model, filters=None): filters = filters or {} admin_class = ralph_site._registry[model] request = RequestFactory().get( - reverse('admin:{}_{}_export'.format( - model._meta.app_label, model._meta.model_name - )), - filters + reverse( + "admin:{}_{}_export".format( + model._meta.app_label, model._meta.model_name + ) + ), + filters, ) request.user = self.user file_format = RawFormat() queryset = admin_class.get_export_queryset(request) - export_data = admin_class.get_export_data(file_format, queryset, request=request) + export_data = admin_class.get_export_data( + file_format, queryset, request=request + ) return export_data def _init(self, num=10): @@ -64,17 +68,18 @@ def _test_queries_count(self, func, nums=(10, 20), max_queries=10): first, second = nums self._init(first) - with CaptureQueriesContext(connections['default']) as cqc: + with CaptureQueriesContext(connections["default"]) as cqc: func() first_queries = len(cqc) self._init(second) - with CaptureQueriesContext(connections['default']) as cqc: + with CaptureQueriesContext(connections["default"]) as cqc: func() second_queries = len(cqc) self.assertEqual( - first_queries, second_queries, - msg=f'Different queries count. First: {first_queries}, second {second_queries}' + first_queries, + second_queries, + msg=f"Different queries count. First: {first_queries}, second {second_queries}", ) self.assertLessEqual(second_queries, max_queries) @@ -110,28 +115,27 @@ def _init(self, num=10): self.data_center_assets_map[dca.id] = dca def test_data_center_asset_export_queries_count(self): - self._test_queries_count(func=lambda: self._export( - DataCenterAsset - ), max_queries=12) + self._test_queries_count( + func=lambda: self._export(DataCenterAsset), max_queries=12 + ) def test_data_center_asset_export_filtered(self): self._init(10) first_id = next(iter(self.data_center_assets_map.keys())) - with CaptureQueriesContext(connections['default']) as cqc: - export_data = self._export( - DataCenterAsset, filters={'id': first_id} - ) + with CaptureQueriesContext(connections["default"]) as cqc: + export_data = self._export(DataCenterAsset, filters={"id": first_id}) queries = len(cqc) self.assertEqual(len(export_data.dict), 1) self.assertLessEqual(queries, 12) + class DataCenterAssetExporterTestCaseWithParent(DataCenterAssetExporterTestCase): def _init(self, num=10): self.data_center_assets = DataCenterAssetFullFactory.create_batch(num) self.data_center_assets_map = {} for i, dca in enumerate(self.data_center_assets, start=num * 2): dca.parent = DataCenterAssetFullFactory() - dca.parent.management_ip = '10.20.30.{}'.format(i) + dca.parent.management_ip = "10.20.30.{}".format(i) dca.save() self.data_center_assets_map[dca.id] = dca self.data_center_assets_map[dca.parent.id] = dca.parent @@ -140,43 +144,40 @@ def test_data_center_asset_export(self): self._init(10) export_data = self._export(DataCenterAsset) # check if management ip is properly exported - self.assertNotEqual(export_data.dict[0]['management_ip'], '') + self.assertNotEqual(export_data.dict[0]["management_ip"], "") def test_data_center_asset_export_with_parent_queries_count(self): - self._test_queries_count(func=lambda: self._export( - DataCenterAsset - ), max_queries=12) + self._test_queries_count( + func=lambda: self._export(DataCenterAsset), max_queries=12 + ) def test_data_center_asset_export_with_parent(self): self._init(10) - export_data = self._export( - DataCenterAsset, filters={'parent__isnull': False} - ) + export_data = self._export(DataCenterAsset, filters={"parent__isnull": False}) - dca_with_parent = next(dca for dca in export_data.dict if dca['parent']) - dca_0_parent = self.data_center_assets_map[int(dca_with_parent['parent'])] + dca_with_parent = next(dca for dca in export_data.dict if dca["parent"]) + dca_0_parent = self.data_center_assets_map[int(dca_with_parent["parent"])] # check if parent management ip is properly exported - self.assertNotEqual(dca_with_parent['parent_management_ip'], '') - self.assertEqual(dca_with_parent['parent_str'], dca_0_parent.baseobject_ptr._str_with_type) + self.assertNotEqual(dca_with_parent["parent_management_ip"], "") + self.assertEqual( + dca_with_parent["parent_str"], dca_0_parent.baseobject_ptr._str_with_type + ) @ddt class BaseObjectsSupportExporterTestCase(SimulateAdminExportTestCase): - def test_support_export_works_with_support_without_price(self): support = SupportFactory(price=None) BaseObjectsSupportFactory(support=support) export_data = self._export(BaseObjectsSupport) - self.assertEqual(export_data.dict[0]['support__price'], '') - self.assertEqual( - export_data.dict[0]['support__price_per_object'], '0.00' - ) + self.assertEqual(export_data.dict[0]["support__price"], "") + self.assertEqual(export_data.dict[0]["support__price_per_object"], "0.00") @unpack @data( - (Decimal('11477.95'), 11, Decimal('1043.45')), - (Decimal('10000'), 1, Decimal('10000.00')), - (Decimal('0.0'), 100, Decimal('0.00')) + (Decimal("11477.95"), 11, Decimal("1043.45")), + (Decimal("10000"), 1, Decimal("10000.00")), + (Decimal("0.0"), 100, Decimal("0.00")), ) def test_get_content_type_for_model( self, support_price, objects_count, expected_price @@ -185,6 +186,5 @@ def test_get_content_type_for_model( BaseObjectsSupportFactory.create_batch(objects_count, support=support) export_data = self._export(BaseObjectsSupport) self.assertEqual( - export_data.dict[0]['support__price_per_object'], - str(expected_price) + export_data.dict[0]["support__price_per_object"], str(expected_price) ) diff --git a/src/ralph/data_importer/tests/test_fields.py b/src/ralph/data_importer/tests/test_fields.py index 938d2268ae..f8e0da629d 100644 --- a/src/ralph/data_importer/tests/test_fields.py +++ b/src/ralph/data_importer/tests/test_fields.py @@ -5,10 +5,7 @@ from ralph.assets.models import BaseObject from ralph.back_office.tests.factories import BackOfficeAssetFactory from ralph.data_importer.fields import ThroughField -from ralph.data_importer.widgets import ( - ManyToManyThroughWidget, - UserManyToManyWidget -) +from ralph.data_importer.widgets import ManyToManyThroughWidget, UserManyToManyWidget from ralph.licences.models import BaseObjectLicence, LicenceUser from ralph.licences.tests.factories import LicenceFactory @@ -24,44 +21,38 @@ def setUpClass(cls): cls.licence2 = LicenceFactory() def setUp(self): - LicenceUser.objects.create( - licence=self.licence, user=self.users[0] - ) + LicenceUser.objects.create(licence=self.licence, user=self.users[0]) for user in self.delete_users: - LicenceUser.objects.create( - licence=self.licence, user=user - ) + LicenceUser.objects.create(licence=self.licence, user=user) BaseObjectLicence.objects.create( - licence=self.licence, base_object=self.back_office_assets[0], + licence=self.licence, + base_object=self.back_office_assets[0], ) BaseObjectLicence.objects.create( - licence=self.licence, base_object=self.back_office_assets[1], + licence=self.licence, + base_object=self.back_office_assets[1], ) - LicenceUser.objects.create( - licence=self.licence2, user=self.users[0] - ) - LicenceUser.objects.create( - licence=self.licence2, user=self.users[3] - ) - LicenceUser.objects.create( - licence=self.licence2, user=self.delete_users[0] - ) + LicenceUser.objects.create(licence=self.licence2, user=self.users[0]) + LicenceUser.objects.create(licence=self.licence2, user=self.users[3]) + LicenceUser.objects.create(licence=self.licence2, user=self.delete_users[0]) BaseObjectLicence.objects.create( - licence=self.licence2, base_object=self.back_office_assets[1], + licence=self.licence2, + base_object=self.back_office_assets[1], ) BaseObjectLicence.objects.create( - licence=self.licence2, base_object=self.back_office_assets[2], + licence=self.licence2, + base_object=self.back_office_assets[2], ) def test_users_through_field(self): field = ThroughField( through_model=LicenceUser, - through_from_field_name='licence', - through_to_field_name='user', - attribute='users', - column_name='users', - widget=UserManyToManyWidget(model=get_user_model()) + through_from_field_name="licence", + through_to_field_name="user", + attribute="users", + column_name="users", + widget=UserManyToManyWidget(model=get_user_model()), ) self.assertEqual(self.licence.users.all().count(), 3) @@ -71,8 +62,7 @@ def test_users_through_field(self): # Add and remove with self.assertNumQueries(5): field.save( - self.licence, - {'users': ','.join([i.username for i in self.users])} + self.licence, {"users": ",".join([i.username for i in self.users])} ) self.assertEqual(self.licence.users.all().count(), 4) @@ -80,18 +70,14 @@ def test_users_through_field(self): # Not remove users = self.users + [UserFactory()] with self.assertNumQueries(3): - field.save( - self.licence, - {'users': ','.join([i.username for i in users])} - ) + field.save(self.licence, {"users": ",".join([i.username for i in users])}) self.assertEqual(self.licence.users.all().count(), 5) # Remove with self.assertNumQueries(4): field.save( - self.licence, - {'users': ','.join([i.username for i in users[:4]])} + self.licence, {"users": ",".join([i.username for i in users[:4]])} ) self.assertEqual(self.licence.users.all().count(), 4) @@ -99,8 +85,7 @@ def test_users_through_field(self): # Update with self.assertNumQueries(2): field.save( - self.licence, - {'users': ','.join([i.username for i in users[:4]])} + self.licence, {"users": ",".join([i.username for i in users[:4]])} ) self.assertEqual(self.licence.users.all().count(), 4) @@ -110,16 +95,16 @@ def test_users_through_field(self): def _get_base_objects_through_field(self): return ThroughField( - column_name='base_objects', - attribute='base_objects', + column_name="base_objects", + attribute="base_objects", widget=ManyToManyThroughWidget( model=BaseObjectLicence, related_model=BaseObject, - through_field='base_object', + through_field="base_object", ), through_model=BaseObjectLicence, - through_from_field_name='licence', - through_to_field_name='base_object' + through_from_field_name="licence", + through_to_field_name="base_object", ) def test_through_field_only_add(self): @@ -127,15 +112,10 @@ def test_through_field_only_add(self): self.assertEqual(self.licence.base_objects.all().count(), 2) ids = [i.pk for i in self.back_office_assets] with self.assertNumQueries(3): - field.save( - self.licence, - {'base_objects': ','.join(map(str, ids))} - ) + field.save(self.licence, {"base_objects": ",".join(map(str, ids))}) self.assertEqual(self.licence.base_objects.all().count(), 4) - self.assertCountEqual( - [bo.pk for bo in self.licence.base_objects.all()], ids - ) + self.assertCountEqual([bo.pk for bo in self.licence.base_objects.all()], ids) # Make sure it doesn't touch other licences self.assertEqual(self.licence2.base_objects.all().count(), 2) @@ -144,15 +124,10 @@ def test_through_field_only_remove(self): self.assertEqual(self.licence.base_objects.all().count(), 2) ids = [self.back_office_assets[0].pk] with self.assertNumQueries(4): - field.save( - self.licence, - {'base_objects': ','.join(map(str, ids))} - ) + field.save(self.licence, {"base_objects": ",".join(map(str, ids))}) self.assertEqual(self.licence.base_objects.all().count(), 1) - self.assertCountEqual( - [bo.pk for bo in self.licence.base_objects.all()], ids - ) + self.assertCountEqual([bo.pk for bo in self.licence.base_objects.all()], ids) # Make sure it doesn't touch other licences self.assertEqual(self.licence2.base_objects.all().count(), 2) @@ -163,16 +138,10 @@ def test_through_field_add_and_remove(self): self.back_office_assets[1].pk, self.back_office_assets[2].pk, self.back_office_assets[3].pk, - ] with self.assertNumQueries(5): - field.save( - self.licence, - {'base_objects': ','.join(map(str, ids))} - ) + field.save(self.licence, {"base_objects": ",".join(map(str, ids))}) self.assertEqual(self.licence.base_objects.all().count(), 3) - self.assertCountEqual( - [bo.pk for bo in self.licence.base_objects.all()], ids - ) + self.assertCountEqual([bo.pk for bo in self.licence.base_objects.all()], ids) # Make sure it doesn't touch other licences self.assertEqual(self.licence2.base_objects.all().count(), 2) diff --git a/src/ralph/data_importer/tests/test_widgets.py b/src/ralph/data_importer/tests/test_widgets.py index b2c21fb3d3..59de85aa99 100644 --- a/src/ralph/data_importer/tests/test_widgets.py +++ b/src/ralph/data_importer/tests/test_widgets.py @@ -3,64 +3,56 @@ from ralph.assets.models import BaseObject from ralph.data_importer.widgets import ( ExportManyToManyStrTroughWidget, - ManyToManyThroughWidget + ManyToManyThroughWidget, ) from ralph.licences.models import BaseObjectLicence -from ralph.licences.tests.factories import ( - DataCenterAssetLicenceFactory, - LicenceFactory -) +from ralph.licences.tests.factories import DataCenterAssetLicenceFactory, LicenceFactory class ManyToManyThroughWidgetTestCase(TestCase): def setUp(self): self.licence = LicenceFactory() DataCenterAssetLicenceFactory.create_batch(3, licence=self.licence) - self.base_objects_ids = [ - bo.pk for bo in self.licence.base_objects.all() - ] + self.base_objects_ids = [bo.pk for bo in self.licence.base_objects.all()] self.widget = ManyToManyThroughWidget( model=BaseObjectLicence, related_model=BaseObject, - through_field='base_object' + through_field="base_object", ) def test_clean(self): - result = self.widget.clean(','.join(map(str, self.base_objects_ids))) + result = self.widget.clean(",".join(map(str, self.base_objects_ids))) self.assertCountEqual( - result, - BaseObject.objects.filter(pk__in=self.base_objects_ids) + result, BaseObject.objects.filter(pk__in=self.base_objects_ids) ) def test_clean_empty_value(self): - result = self.widget.clean('') + result = self.widget.clean("") self.assertCountEqual(result, BaseObject.objects.none()) self.assertEqual(result.model, BaseObject) def test_render(self): result = self.widget.render(self.licence.baseobjectlicence_set.all()) - self.assertCountEqual( - map(int, result.split(',')), self.base_objects_ids - ) + self.assertCountEqual(map(int, result.split(",")), self.base_objects_ids) class ExportManyToManyStrThroughWidgetTestCase(TestCase): def setUp(self): self.licence = LicenceFactory() DataCenterAssetLicenceFactory.create_batch(3, licence=self.licence) - self.base_objects_ids = [ - bo.pk for bo in self.licence.base_objects.all() - ] + self.base_objects_ids = [bo.pk for bo in self.licence.base_objects.all()] self.widget = ExportManyToManyStrTroughWidget( model=BaseObjectLicence, related_model=BaseObject, - through_field='base_object' + through_field="base_object", ) def test_render(self): result = self.widget.render(self.licence.baseobjectlicence_set.all()) - self.assertCountEqual(result.split(','), [ - str(obj) for obj in BaseObject.objects.filter( - pk__in=self.base_objects_ids - ) - ]) + self.assertCountEqual( + result.split(","), + [ + str(obj) + for obj in BaseObject.objects.filter(pk__in=self.base_objects_ids) + ], + ) diff --git a/src/ralph/data_importer/widgets.py b/src/ralph/data_importer/widgets.py index d03b2baada..7a18427aba 100644 --- a/src/ralph/data_importer/widgets.py +++ b/src/ralph/data_importer/widgets.py @@ -24,24 +24,15 @@ def get_imported_obj(model, old_pk): """ content_type = ContentType.objects.get_for_model(model) imported_obj = ImportedObjects.objects.filter( - content_type=content_type, - old_object_pk=str(old_pk) + content_type=content_type, old_object_pk=str(old_pk) ).first() if not imported_obj: - msg = ( - "Record with pk %s not found for model %s of '%s'" - ) - logger.warning( - msg, - str(old_pk), - model._meta.model_name, - content_type - ) + msg = "Record with pk %s not found for model %s of '%s'" + logger.warning(msg, str(old_pk), model._meta.model_name, content_type) return content_type, imported_obj class UserWidget(widgets.ForeignKeyWidget): - """Widget for Ralph User Foreign Key field.""" def clean(self, value, *args, **kwargs): @@ -51,19 +42,16 @@ def clean(self, value, *args, **kwargs): username=value, ) if created: - logger.warning( - 'User not found: %s create a new.', value - ) + logger.warning("User not found: %s create a new.", value) return result def render(self, value, obj=None): if value: return value.username - return '' + return "" class UserManyToManyWidget(widgets.ManyToManyWidget): - """Widget for many Ralph Users Foreign Key field.""" def clean(self, value, *args, **kwargs): @@ -81,6 +69,7 @@ class ManyToManyThroughWidget(widgets.ManyToManyWidget): Widget for many-to-many relations with through table. This widget accept or return list of related models PKs (other-end of through table). """ + def __init__(self, through_field, related_model, *args, **kwargs): """ Args: @@ -97,9 +86,7 @@ def __init__(self, through_field, related_model, *args, **kwargs): def clean(self, value, *args, **kwargs): if not value: return self.related_model.objects.none() - return self.related_model.objects.filter( - pk__in=value.split(self.separator) - ) + return self.related_model.objects.filter(pk__in=value.split(self.separator)) def render(self, value, obj=None): return self.separator.join( @@ -113,7 +100,6 @@ def render(self, value, obj=None): class ExportManyToManyStrWidget(widgets.ManyToManyWidget): - def render(self, value, obj=None): return self.separator.join([str(obj) for obj in value.all()]) @@ -123,6 +109,7 @@ class ExportManyToManyStrTroughWidget(ManyToManyThroughWidget): Exporter-equivalent of `ManyToManyThroughWidget` - return str of whole object instead of pk. """ + def render(self, value, obj=None): return self.separator.join( [str(getattr(obj, self.through_field)) for obj in value.all()] @@ -130,7 +117,6 @@ def render(self, value, obj=None): class BaseObjectManyToManyWidget(widgets.ManyToManyWidget): - """Widget for BO/DC base objects.""" def clean(self, value, *args, **kwargs): @@ -143,19 +129,16 @@ def clean(self, value, *args, **kwargs): # TODO: more types ) imported_obj_ids = ImportedObjects.objects.filter( - content_type__in=content_types.values(), - old_object_pk__in=ids - ).values_list('object_pk', 'content_type') + content_type__in=content_types.values(), old_object_pk__in=ids + ).values_list("object_pk", "content_type") base_object_ids = [] for model, content_type in content_types.items(): - model_ids = [ - i[0] for i in imported_obj_ids if i[1] == content_type.pk - ] + model_ids = [i[0] for i in imported_obj_ids if i[1] == content_type.pk] base_object_ids.extend( model.objects.filter( pk__in=model_ids, ).values_list( - 'baseobject_ptr', + "baseobject_ptr", flat=True, ) ) @@ -163,7 +146,6 @@ def clean(self, value, *args, **kwargs): class BaseObjectWidget(widgets.ForeignKeyWidget): - """Widget for BO/DC base objects.""" def clean(self, value, *args, **kwargs): @@ -171,7 +153,7 @@ def clean(self, value, *args, **kwargs): return None result = None asset_type, asset_id = value.split("|") # dc/bo, pk - models = {'bo': BackOfficeAsset, 'dc': DataCenterAsset} + models = {"bo": BackOfficeAsset, "dc": DataCenterAsset} model = models.get(asset_type.lower()) if not model: return None @@ -179,9 +161,7 @@ def clean(self, value, *args, **kwargs): content_type, imported_obj = get_imported_obj(model, asset_id) if imported_obj: - result = model.objects.filter( - pk=imported_obj.object_pk - ).first() + result = model.objects.filter(pk=imported_obj.object_pk).first() if result: return result.baseobject_ptr @@ -189,15 +169,12 @@ def clean(self, value, *args, **kwargs): class ImportedForeignKeyWidget(widgets.ForeignKeyWidget): - """Widget for ForeignKey fields for which can not define unique.""" def clean(self, value, *args, **kwargs): if settings.MAP_IMPORTED_ID_TO_NEW_ID: if value: - content_type, imported_obj = get_imported_obj( - self.model, value - ) + content_type, imported_obj = get_imported_obj(self.model, value) if imported_obj: value = imported_obj.object_pk return super().clean(value) @@ -209,7 +186,6 @@ def clean(self, value, *args, **kwargs): class AssetServiceEnvWidget(widgets.ForeignKeyWidget): - """Widget for AssetServiceEnv Foreign Key field. CSV field format Service.name|Environment.name @@ -224,8 +200,7 @@ def clean(self, value, *args, **kwargs): else: service, enviroment = value.split("|") value = ServiceEnvironment.objects.get( - service__name=service, - environment__name=enviroment + service__name=service, environment__name=enviroment ) except (ValueError, ServiceEnvironment.DoesNotExist): value = None @@ -234,14 +209,10 @@ def clean(self, value, *args, **kwargs): def render(self, value, obj=None): if value is None: return "" - return "{}|{}".format( - value.service.name, - value.environment.name - ) + return "{}|{}".format(value.service.name, value.environment.name) class AssetServiceUidWidget(widgets.ForeignKeyWidget): - def clean(self, value, *args, **kwargs): if not value: return None @@ -251,8 +222,7 @@ def clean(self, value, *args, **kwargs): else: service, enviroment = value.split("|") value = ServiceEnvironment.objects.get( - service__name=service, - environment__name=enviroment + service__name=service, environment__name=enviroment ) except (ValueError, ServiceEnvironment.DoesNotExist): value = None @@ -276,24 +246,24 @@ class IPManagementWidget(widgets.ManyToManyWidget): ip. This because management ip is seperate model which can't be created wihtout DataCenterAsset (and DataCenterAsset is the result of importing). """ + def clean(self, value, *args, **kwargs): return value def render(self, value, obj=None): - return value or '' + return value or "" class BaseObjectServiceNamesM2MWidget(widgets.ManyToManyWidget): def render(self, value, obj=None): - return self.separator.join([ - bo.service.name if bo.service else '-' - for bo in value.all() - ]) + return self.separator.join( + [bo.service.name if bo.service else "-" for bo in value.all()] + ) class PriceAmountWidget(widgets.Widget): def render(self, value, obj=None): - return '{0:.2f}'.format(value.amount) + return "{0:.2f}".format(value.amount) class PriceCurrencyWidget(widgets.Widget): diff --git a/src/ralph/dc_view/__init__.py b/src/ralph/dc_view/__init__.py index 85b5d8a94a..7e8f500b1b 100644 --- a/src/ralph/dc_view/__init__.py +++ b/src/ralph/dc_view/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.dc_view.apps.DCViewConfig' +default_app_config = "ralph.dc_view.apps.DCViewConfig" diff --git a/src/ralph/dc_view/apps.py b/src/ralph/dc_view/apps.py index abf90fa1de..3c7b41fcd1 100644 --- a/src/ralph/dc_view/apps.py +++ b/src/ralph/dc_view/apps.py @@ -3,8 +3,8 @@ class DCViewConfig(RalphAppConfig): - name = 'ralph.dc_view' - verbose_name = 'DC View' + name = "ralph.dc_view" + verbose_name = "DC View" def ready(self): super().ready() diff --git a/src/ralph/dc_view/serializers/models_serializer.py b/src/ralph/dc_view/serializers/models_serializer.py index 61f27b7994..f6ca7395b8 100644 --- a/src/ralph/dc_view/serializers/models_serializer.py +++ b/src/ralph/dc_view/serializers/models_serializer.py @@ -8,13 +8,13 @@ DataCenterAsset, Rack, RackAccessory, - ServerRoom + ServerRoom, ) -TYPE_EMPTY = 'empty' -TYPE_ACCESSORY = 'accessory' -TYPE_ASSET = 'asset' -TYPE_PDU = 'pdu' +TYPE_EMPTY = "empty" +TYPE_ACCESSORY = "accessory" +TYPE_ASSET = "asset" +TYPE_PDU = "pdu" class AdminLinkMixin(serializers.ModelSerializer): @@ -25,23 +25,26 @@ class AdminLinkMixin(serializers.ModelSerializer): def admin_link(self, obj): if isinstance(obj, OrderedDict): return "" - return reverse('admin:{app_label}_{model_name}_change'.format( - app_label=obj._meta.app_label, - model_name=obj._meta.model_name, - ), args=(obj.id,)) + return reverse( + "admin:{app_label}_{model_name}_change".format( + app_label=obj._meta.app_label, + model_name=obj._meta.model_name, + ), + args=(obj.id,), + ) class DataCenterAssetSerializerBase(serializers.ModelSerializer): - model = serializers.CharField(source='model.name') - service = serializers.SerializerMethodField('get_service_env') - orientation = serializers.CharField(source='get_orientation_desc') - url = serializers.CharField(source='get_absolute_url') + model = serializers.CharField(source="model.name") + service = serializers.SerializerMethodField("get_service_env") + orientation = serializers.CharField(source="get_orientation_desc") + url = serializers.CharField(source="get_absolute_url") def get_service_env(self, obj): try: service_name = obj.service_env.service.name except AttributeError: - service_name = '' + service_name = "" return str(service_name) def get_orientation_desc(self, obj): @@ -49,61 +52,75 @@ def get_orientation_desc(self, obj): class ServerRoomtSerializer(serializers.ModelSerializer): - class Meta: model = ServerRoom - fields = ( - 'id', 'name' - ) + fields = ("id", "name") class RelatedAssetSerializer(DataCenterAssetSerializerBase): - class Meta: model = DataCenterAsset fields = ( - 'id', 'model', 'barcode', 'sn', 'slot_no', 'hostname', 'service', - 'orientation', 'url', + "id", + "model", + "barcode", + "sn", + "slot_no", + "hostname", + "service", + "orientation", + "url", ) class DataCenterAssetSerializer(DataCenterAssetSerializerBase): - category = serializers.CharField(source='model.category.name') - height = serializers.FloatField(source='model.height_of_device') - front_layout = serializers.CharField( - source='model.get_front_layout_class' - ) - back_layout = serializers.CharField(source='model.get_back_layout_class') + category = serializers.CharField(source="model.category.name") + height = serializers.FloatField(source="model.height_of_device") + front_layout = serializers.CharField(source="model.get_front_layout_class") + back_layout = serializers.CharField(source="model.get_back_layout_class") children = RelatedAssetSerializer( - source='get_related_assets', + source="get_related_assets", many=True, ) - _type = serializers.SerializerMethodField('get_type') - management_ip = serializers.SerializerMethodField('get_management') - orientation = serializers.SerializerMethodField('get_orientation_desc') - url = serializers.CharField(source='get_absolute_url') + _type = serializers.SerializerMethodField("get_type") + management_ip = serializers.SerializerMethodField("get_management") + orientation = serializers.SerializerMethodField("get_orientation_desc") + url = serializers.CharField(source="get_absolute_url") def get_type(self, obj): return TYPE_ASSET def get_management(self, obj): - return obj.management_ip or '' + return obj.management_ip or "" class Meta: model = DataCenterAsset fields = ( - 'id', 'model', 'category', 'height', 'front_layout', - 'back_layout', 'barcode', 'sn', 'position', - 'children', '_type', 'hostname', 'management_ip', - 'orientation', 'service', 'remarks', 'url', + "id", + "model", + "category", + "height", + "front_layout", + "back_layout", + "barcode", + "sn", + "position", + "children", + "_type", + "hostname", + "management_ip", + "orientation", + "service", + "remarks", + "url", ) class RackAccessorySerializer(serializers.ModelSerializer): - type = serializers.CharField(source='accessory.name') - _type = serializers.SerializerMethodField('get_type') - orientation = serializers.SerializerMethodField('get_orientation_desc') - url = serializers.CharField(source='get_absolute_url') + type = serializers.CharField(source="accessory.name") + _type = serializers.SerializerMethodField("get_type") + orientation = serializers.SerializerMethodField("get_orientation_desc") + url = serializers.CharField(source="get_absolute_url") def get_type(self, obj): return TYPE_ACCESSORY @@ -113,64 +130,71 @@ def get_orientation_desc(self, obj): class Meta: model = RackAccessory - fields = ('position', 'orientation', 'remarks', 'type', '_type', 'url') + fields = ("position", "orientation", "remarks", "type", "_type", "url") class PDUSerializer(serializers.ModelSerializer): - model = serializers.CharField(source='model.name') - orientation = serializers.CharField(source='get_orientation_desc') - url = serializers.CharField(source='get_absolute_url') + model = serializers.CharField(source="model.name") + orientation = serializers.CharField(source="get_orientation_desc") + url = serializers.CharField(source="get_absolute_url") def get_type(self, obj): return TYPE_PDU class Meta: model = DataCenterAsset - fields = ('model', 'sn', 'orientation', 'url') + fields = ("model", "sn", "orientation", "url") class RackBaseSerializer(serializers.ModelSerializer): - free_u = serializers.IntegerField(source='get_free_u', read_only=True) - orientation = serializers.CharField(source='get_orientation_desc') + free_u = serializers.IntegerField(source="get_free_u", read_only=True) + orientation = serializers.CharField(source="get_orientation_desc") class Meta: model = Rack fields = ( - 'id', 'name', 'server_room', 'max_u_height', - 'visualization_col', 'visualization_row', 'free_u', 'description', - 'orientation', 'reverse_ordering' + "id", + "name", + "server_room", + "max_u_height", + "visualization_col", + "visualization_row", + "free_u", + "description", + "orientation", + "reverse_ordering", ) def update(self, data): - data['server_room'] = ServerRoom.objects.get( - pk=data['server_room'] - ) - data['orientation'] = RackOrientation.id_from_name(data['orientation']) + data["server_room"] = ServerRoom.objects.get(pk=data["server_room"]) + data["orientation"] = RackOrientation.id_from_name(data["orientation"]) return super(RackBaseSerializer, self).update(self.instance, data) def create(self, data): - data['orientation'] = RackOrientation.id_from_name(data['orientation']) - data['server_room'] = ServerRoom.objects.get( - pk=int(data['server_room']) - ) + data["orientation"] = RackOrientation.id_from_name(data["orientation"]) + data["server_room"] = ServerRoom.objects.get(pk=int(data["server_room"])) return Rack.objects.create(**data) class RackSerializer(AdminLinkMixin, RackBaseSerializer): - rack_admin_url = serializers.SerializerMethodField('admin_link') + rack_admin_url = serializers.SerializerMethodField("admin_link") class Meta(RackBaseSerializer.Meta): - fields = RackBaseSerializer.Meta.fields + ('rack_admin_url',) + fields = RackBaseSerializer.Meta.fields + ("rack_admin_url",) class SRSerializer(AdminLinkMixin, serializers.ModelSerializer): - rack_set = RackSerializer(source='racks', many=True) - admin_link = serializers.SerializerMethodField('admin_link') + rack_set = RackSerializer(source="racks", many=True) + admin_link = serializers.SerializerMethodField("admin_link") class Meta: model = ServerRoom fields = ( - 'id', 'name', 'visualization_cols_num', - 'visualization_rows_num', 'rack_set', 'admin_link' + "id", + "name", + "visualization_cols_num", + "visualization_rows_num", + "rack_set", + "admin_link", ) depth = 1 diff --git a/src/ralph/dc_view/tests.py b/src/ralph/dc_view/tests.py index 58c218ead6..aae6ee43c7 100644 --- a/src/ralph/dc_view/tests.py +++ b/src/ralph/dc_view/tests.py @@ -9,7 +9,7 @@ DataCenterAssetModelFactory, EnvironmentFactory, ServiceEnvironment, - ServiceFactory + ServiceFactory, ) from ralph.data_center.models.choices import Orientation from ralph.data_center.tests.factories import ( @@ -17,51 +17,39 @@ DataCenterAssetFactory, RackAccessoryFactory, RackFactory, - ServerRoomFactory -) -from ralph.dc_view.serializers.models_serializer import ( - TYPE_ACCESSORY, - TYPE_ASSET + ServerRoomFactory, ) +from ralph.dc_view.serializers.models_serializer import TYPE_ACCESSORY, TYPE_ASSET class TestRestAssetInfoPerRack(TestCase): - def setUp(self): - get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' - ) + get_user_model().objects.create_superuser("test", "test@test.test", "test") self.client = APIClient() - self.client.login(username='test', password='test') + self.client.login(username="test", password="test") environment = EnvironmentFactory() - service = ServiceFactory(name='Service1') + service = ServiceFactory(name="Service1") service_env = ServiceEnvironment.objects.create( - service=service, - environment=environment - ) - asset_model = DataCenterAssetModelFactory( - type=ObjectModelType.data_center + service=service, environment=environment ) + asset_model = DataCenterAssetModelFactory(type=ObjectModelType.data_center) self.server_room = ServerRoomFactory() self.accesory_1 = AccessoryFactory() - self.rack_1 = RackFactory( - server_room=self.server_room, - max_u_height=3 - ) + self.rack_1 = RackFactory(server_room=self.server_room, max_u_height=3) self.asset_1 = DataCenterAssetFactory( service_env=service_env, position=1, - slot_no='', + slot_no="", force_depreciation=False, model=asset_model, rack=self.rack_1, ) - self.asset_1.management_ip = '10.15.25.45' + self.asset_1.management_ip = "10.15.25.45" self.pdu_1 = DataCenterAssetFactory( service_env=service_env, @@ -75,7 +63,7 @@ def setUp(self): rack=self.rack_1, orientation=Orientation.front, accessory=self.accesory_1, - position=1 + position=1, ) def tearDown(self): @@ -83,62 +71,59 @@ def tearDown(self): def test_get(self): returned_json = json.loads( - self.client.get( - '/api/rack/{0}/'.format(self.rack_1.id) - ).content.decode() + self.client.get("/api/rack/{0}/".format(self.rack_1.id)).content.decode() ) self.maxDiff = None expected_json = { - 'info': { - 'id': self.rack_1.id, - 'name': self.rack_1.name, - 'server_room': self.rack_1.server_room.id, - 'max_u_height': self.rack_1.max_u_height, - 'visualization_col': self.rack_1.visualization_col, - 'visualization_row': self.rack_1.visualization_row, - 'free_u': self.rack_1.get_free_u(), - 'description': '{}'.format(self.rack_1.description), - 'orientation': '{}'.format(self.rack_1.get_orientation_desc()), - 'rack_admin_url': self.rack_1.get_absolute_url(), - 'reverse_ordering': self.rack_1.reverse_ordering + "info": { + "id": self.rack_1.id, + "name": self.rack_1.name, + "server_room": self.rack_1.server_room.id, + "max_u_height": self.rack_1.max_u_height, + "visualization_col": self.rack_1.visualization_col, + "visualization_row": self.rack_1.visualization_row, + "free_u": self.rack_1.get_free_u(), + "description": "{}".format(self.rack_1.description), + "orientation": "{}".format(self.rack_1.get_orientation_desc()), + "rack_admin_url": self.rack_1.get_absolute_url(), + "reverse_ordering": self.rack_1.reverse_ordering, }, - 'devices': - [ + "devices": [ { - '_type': TYPE_ASSET, - 'id': self.asset_1.id, - 'hostname': self.asset_1.hostname, - 'category': self.asset_1.model.category.name, - 'barcode': self.asset_1.barcode, - 'sn': self.asset_1.sn, - 'height': float(self.asset_1.model.height_of_device), - 'position': self.asset_1.position, - 'model': self.asset_1.model.name, - 'children': [], - 'front_layout': '', - 'back_layout': '', - 'management_ip': self.asset_1.management_ip, - 'orientation': 'front', - 'remarks': '', - 'service': 'Service1', - 'url': self.asset_1.get_absolute_url() + "_type": TYPE_ASSET, + "id": self.asset_1.id, + "hostname": self.asset_1.hostname, + "category": self.asset_1.model.category.name, + "barcode": self.asset_1.barcode, + "sn": self.asset_1.sn, + "height": float(self.asset_1.model.height_of_device), + "position": self.asset_1.position, + "model": self.asset_1.model.name, + "children": [], + "front_layout": "", + "back_layout": "", + "management_ip": self.asset_1.management_ip, + "orientation": "front", + "remarks": "", + "service": "Service1", + "url": self.asset_1.get_absolute_url(), }, { - '_type': TYPE_ACCESSORY, - 'orientation': 'front', - 'position': self.rack1_accessory.position, - 'remarks': self.rack1_accessory.remarks, - 'type': self.rack1_accessory.accessory.name, - 'url': self.rack1_accessory.get_absolute_url(), + "_type": TYPE_ACCESSORY, + "orientation": "front", + "position": self.rack1_accessory.position, + "remarks": self.rack1_accessory.remarks, + "type": self.rack1_accessory.accessory.name, + "url": self.rack1_accessory.get_absolute_url(), }, ], - 'pdus': [ + "pdus": [ { - 'model': self.pdu_1.model.name, - 'orientation': 'left', - 'sn': self.pdu_1.sn, - 'url': self.pdu_1.get_absolute_url() + "model": self.pdu_1.model.name, + "orientation": "left", + "sn": self.pdu_1.sn, + "url": self.pdu_1.get_absolute_url(), }, - ] + ], } self.assertEqual(returned_json, expected_json) diff --git a/src/ralph/dc_view/urls/api.py b/src/ralph/dc_view/urls/api.py index 6fb1be4560..ef11f0c596 100644 --- a/src/ralph/dc_view/urls/api.py +++ b/src/ralph/dc_view/urls/api.py @@ -4,11 +4,11 @@ urlpatterns = [ url( - r'^rack/(?P\d+)/?$', + r"^rack/(?P\d+)/?$", DCAssetsView.as_view(), ), url( - r'^server_room/(?P\d+)/?$', + r"^server_room/(?P\d+)/?$", SRRacksAPIView.as_view(), ), ] diff --git a/src/ralph/dc_view/urls/ui.py b/src/ralph/dc_view/urls/ui.py index 8cd6988ccd..73d4b6d0b9 100644 --- a/src/ralph/dc_view/urls/ui.py +++ b/src/ralph/dc_view/urls/ui.py @@ -3,12 +3,10 @@ from ralph.dc_view.views.ui import ServerRoomView, SettingsForAngularView urlpatterns = [ + url(r"^dc_view/?$", ServerRoomView.as_view(), name="dc_view"), url( - r'^dc_view/?$', - ServerRoomView.as_view(), - name='dc_view' - ), - url( - r'^settings.js$', SettingsForAngularView.as_view(), name='settings-js', + r"^settings.js$", + SettingsForAngularView.as_view(), + name="settings-js", ), ] diff --git a/src/ralph/dc_view/views/api.py b/src/ralph/dc_view/views/api.py index b081e1fe6c..c5b214728d 100644 --- a/src/ralph/dc_view/views/api.py +++ b/src/ralph/dc_view/views/api.py @@ -9,12 +9,11 @@ RackAccessorySerializer, RackBaseSerializer, RackSerializer, - SRSerializer + SRSerializer, ) class DCAssetsView(APIView): - def get_object(self, pk): try: return Rack.objects.get(id=pk) @@ -22,16 +21,13 @@ def get_object(self, pk): raise Http404 def _get_assets(self, rack): - return DataCenterAssetSerializer( - rack.get_root_assets(), - many=True - ).data + return DataCenterAssetSerializer(rack.get_root_assets(), many=True).data def _get_rack_data(self, rack): return RackSerializer(rack).data def _get_accessories(self, rack): - accessories = RackAccessory.objects.select_related('accessory').filter( + accessories = RackAccessory.objects.select_related("accessory").filter( rack=rack ) return RackAccessorySerializer(accessories, many=True).data @@ -42,16 +38,13 @@ def _get_pdus(self, rack): def get(self, request, rack_id, format=None): rack = self.get_object(rack_id) devices = {} - devices['devices'] = ( - self._get_assets(rack) + self._get_accessories(rack) - ) - devices['pdus'] = self._get_pdus(rack) - devices['info'] = self._get_rack_data(rack) + devices["devices"] = self._get_assets(rack) + self._get_accessories(rack) + devices["pdus"] = self._get_pdus(rack) + devices["info"] = self._get_rack_data(rack) return Response(devices) def put(self, request, rack_id, format=None): - serializer = RackSerializer( - self.get_object(rack_id), data=request.data) + serializer = RackSerializer(self.get_object(rack_id), data=request.data) if serializer.is_valid(): rack = serializer.update(data=request.data) return Response(self._get_rack_data(rack)) @@ -69,6 +62,7 @@ class SRRacksAPIView(APIView): """ Return information of list rack in data center with their positions. """ + def get_object(self, pk): try: return ServerRoom.objects.get(id=pk) @@ -81,6 +75,4 @@ def get(self, request, server_room_id, format=None): :param data_center_id int: data_center id :returns list: list of informations about racks in given data center """ - return Response( - SRSerializer(self.get_object(server_room_id)).data - ) + return Response(SRSerializer(self.get_object(server_room_id)).data) diff --git a/src/ralph/dc_view/views/ui.py b/src/ralph/dc_view/views/ui.py index f76ef65d57..e3054d4643 100644 --- a/src/ralph/dc_view/views/ui.py +++ b/src/ralph/dc_view/views/ui.py @@ -8,24 +8,26 @@ class ServerRoomView(RalphTemplateView): - template_name = 'dc_view/server_room_view.html' + template_name = "dc_view/server_room_view.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_centers'] = DataCenter.objects.annotate( - rooms_count=Count('serverroom') + context["data_centers"] = DataCenter.objects.annotate( + rooms_count=Count("serverroom") ).filter(rooms_count__gt=0) - context['site_header'] = "Ralph 3" + context["site_header"] = "Ralph 3" return context class SettingsForAngularView(RalphTemplateView): - content_type = 'application/javascript' - template_name = 'dc_view/settings_for_angular.js' + content_type = "application/javascript" + template_name = "dc_view/settings_for_angular.js" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['settings'] = json.dumps({ - 'RACK_LISTING_NUMBERING_TOP_TO_BOTTOM': settings.RACK_LISTING_NUMBERING_TOP_TO_BOTTOM, # noqa - }) + context["settings"] = json.dumps( + { + "RACK_LISTING_NUMBERING_TOP_TO_BOTTOM": settings.RACK_LISTING_NUMBERING_TOP_TO_BOTTOM, # noqa + } + ) return context diff --git a/src/ralph/deployment/__init__.py b/src/ralph/deployment/__init__.py index 35a24a27a7..dfece0dc98 100644 --- a/src/ralph/deployment/__init__.py +++ b/src/ralph/deployment/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.deployment.apps.DeploymentConfig' +default_app_config = "ralph.deployment.apps.DeploymentConfig" diff --git a/src/ralph/deployment/admin.py b/src/ralph/deployment/admin.py index 9ab3943887..b79d7a30a3 100644 --- a/src/ralph/deployment/admin.py +++ b/src/ralph/deployment/admin.py @@ -8,75 +8,58 @@ Preboot, PrebootConfiguration, PrebootFile, - PrebootItem + PrebootItem, ) @register(PrebootItem) class PrebootItemAdmin(RalphAdmin): - search_fields = ['name'] + search_fields = ["name"] @register(PrebootConfiguration) class PrebootConfigurationAdmin(PrebootItemAdmin): form = PrebootConfigurationForm fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', 'type', 'configuration' - ) - }), - (_('Additional info'), { - 'fields': ( - 'description', - ) - }), + (_("Basic info"), {"fields": ("name", "type", "configuration")}), + (_("Additional info"), {"fields": ("description",)}), ) - list_filter = ['type'] - list_display = ['name', 'type', 'description'] + list_filter = ["type"] + list_display = ["name", "type", "description"] @register(PrebootFile) class PrebootFileAdmin(PrebootItemAdmin): fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', 'type', 'file' - ) - }), - (_('Additional info'), { - 'fields': ( - 'description', - ) - }), + (_("Basic info"), {"fields": ("name", "type", "file")}), + (_("Additional info"), {"fields": ("description",)}), ) - list_filter = ['type'] - list_display = ['name', 'type', 'description'] + list_filter = ["type"] + list_display = ["name", "type", "description"] @register(Preboot) class PrebootAdmin(RalphAdmin): - raw_id_fields = ['items'] + raw_id_fields = ["items"] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', - 'items', - 'warning_after', - 'critical_after', - 'disappears_after' - ) - }), - (_('Additional info'), { - 'fields': ( - 'description', - ) - }), + ( + _("Basic info"), + { + "fields": ( + "name", + "items", + "warning_after", + "critical_after", + "disappears_after", + ) + }, + ), + (_("Additional info"), {"fields": ("description",)}), ) - list_display = ['name', 'description', 'used_counter'] - search_fields = ['name', 'description'] - list_filter = ['name'] + list_display = ["name", "description", "used_counter"] + search_fields = ["name", "description"] + list_filter = ["name"] @register(Deployment) diff --git a/src/ralph/deployment/apps.py b/src/ralph/deployment/apps.py index be4c158bbc..bd09d97b6c 100644 --- a/src/ralph/deployment/apps.py +++ b/src/ralph/deployment/apps.py @@ -2,8 +2,8 @@ class DeploymentConfig(RalphAppConfig): - name = 'ralph.deployment' - verbose_name = 'Deployment' + name = "ralph.deployment" + verbose_name = "Deployment" def get_load_modules_when_ready(self): - return super().get_load_modules_when_ready() + ['deployment'] + return super().get_load_modules_when_ready() + ["deployment"] diff --git a/src/ralph/deployment/deployment.py b/src/ralph/deployment/deployment.py index 71c4272636..f4c2435e6d 100644 --- a/src/ralph/deployment/deployment.py +++ b/src/ralph/deployment/deployment.py @@ -18,6 +18,7 @@ * Wait for ping """ + import ipaddress import logging import time @@ -47,7 +48,7 @@ logger = logging.getLogger(__name__) -NEXT_FREE = _('') +NEXT_FREE = _("") DEPLOYMENT_MODELS = [DataCenterAsset, VirtualServer] deployment_action = partial(transition_action, models=DEPLOYMENT_MODELS) @@ -107,20 +108,15 @@ def next_free_hostname_choices(actions, objects): """ network_environments = [] for obj in objects: - network_environments.append( - set(obj._get_available_network_environments()) - ) + network_environments.append(set(obj._get_available_network_environments())) # get common part network_environments = set.intersection(*network_environments) hostnames = [ - ( - str(net_env.id), - '{} ({})'.format(net_env.next_free_hostname, net_env) - ) + (str(net_env.id), "{} ({})".format(net_env.next_free_hostname, net_env)) for net_env in network_environments ] if len(objects) == 1: - hostnames += [(OTHER, _('Other'))] + hostnames += [(OTHER, _("Other"))] return hostnames @@ -139,16 +135,11 @@ def next_free_ip_choices(actions, objects): """ networks = [] for obj in objects: - networks.append(set(obj._get_available_networks( - is_broadcasted_in_dhcp=True - ))) + networks.append(set(obj._get_available_networks(is_broadcasted_in_dhcp=True))) # get common part networks = set.intersection(*networks) ips = [ - ( - str(network.id), - '{} ({})'.format(network.get_first_free_ip(), network) - ) + (str(network.id), "{} ({})".format(network.get_first_free_ip(), network)) for network in networks ] return ips @@ -170,7 +161,7 @@ def next_free_ip_choices_wth_other_choice(actions, objects): ips = next_free_ip_choices(actions, objects) # if there is only one object, allow for Other option typed by user if len(objects) == 1: - ips += [(OTHER, _('Other'))] + ips += [(OTHER, _("Other"))] return ips @@ -190,13 +181,16 @@ def mac_choices_for_objects(actions, objects): list of tuples with MAC addresses """ if len(objects) == 1: - return [(eth.id, eth.mac) for eth in objects[0].ethernet_set.filter( - Q(ipaddress__is_management=False) | Q(ipaddress__isnull=True), - mac__isnull=False, - )] + return [ + (eth.id, eth.mac) + for eth in objects[0].ethernet_set.filter( + Q(ipaddress__is_management=False) | Q(ipaddress__isnull=True), + mac__isnull=False, + ) + ] # TODO: when some object has more than one Ethernets (non-mgmt), should # raise exception? - return [('0', _('use first'))] + return [("0", _("use first"))] def dhcp_entries_for_objects(actions, objects): @@ -214,15 +208,18 @@ def dhcp_entries_for_objects(actions, objects): list of tuples with DHCP entries. """ if len(objects) == 1: - return [( - ip.id, - '{} ({}) / {}'.format( - ip.address, - ip.hostname, - # theoritically should never happen... - ip.ethernet.mac if ip.ethernet else None + return [ + ( + ip.id, + "{} ({}) / {}".format( + ip.address, + ip.hostname, + # theoritically should never happen... + ip.ethernet.mac if ip.ethernet else None, + ), ) - ) for ip in objects[0].ipaddresses.filter(dhcp_expose=True)] + for ip in objects[0].ipaddresses.filter(dhcp_expose=True) + ] # TODO: don't allow to run this action when more than one object selected return [] @@ -234,11 +231,11 @@ def _get_non_mgmt_ethernets(instance): Args: instance: BaseObject instance """ - return instance.ethernet_set.filter( - mac__isnull=False - ).exclude( - ipaddress__is_management=True - ).order_by('mac') + return ( + instance.ethernet_set.filter(mac__isnull=False) + .exclude(ipaddress__is_management=True) + .order_by("mac") + ) def check_if_deployment_is_available(instances, **kwargs): @@ -248,13 +245,16 @@ def check_if_deployment_is_available(instances, **kwargs): errors = {} for instance in instances: if ( - isinstance(instance, DataCenterAsset) and - not instance.model.category.allow_deployment + isinstance(instance, DataCenterAsset) + and not instance.model.category.allow_deployment ): - errors[instance] = _(( - 'Deployment is not available for this asset' - ' with category: %(category)s.' - ) % {'category': instance.model.category.name}) + errors[instance] = _( + ( + "Deployment is not available for this asset" + " with category: %(category)s." + ) + % {"category": instance.model.category.name} + ) return errors @@ -265,7 +265,7 @@ def check_mac_address(instances, **kwargs): errors = {} for instance in instances: if not _get_non_mgmt_ethernets(instance): - errors[instance] = _('Non-management MAC address not found') + errors[instance] = _("Non-management MAC address not found") return errors @@ -276,7 +276,7 @@ def check_if_network_environment_exists(instances, **kwargs): errors = {} for instance in instances: if not instance._get_available_network_environments(): - errors[instance] = _('Network environment not found.') + errors[instance] = _("Network environment not found.") return errors @@ -284,20 +284,20 @@ def check_if_network_environment_exists(instances, **kwargs): # transition actions # ============================================================================= @deployment_action( - verbose_name=_('Clean hostname'), + verbose_name=_("Clean hostname"), ) def clean_hostname(cls, instances, **kwargs): """ Clear hostname for each instance """ for instance in instances: - logger.warning('Clearing %s hostname (%s)', instance, instance.hostname) + logger.warning("Clearing %s hostname (%s)", instance, instance.hostname) instance.hostname = None # TODO: hostname nullable? @deployment_action( - verbose_name=_('Clean DNS entries'), - run_after=['clean_hostname'], + verbose_name=_("Clean DNS entries"), + run_after=["clean_hostname"], is_async=True, ) def clean_dns(cls, instances, **kwargs): @@ -309,34 +309,36 @@ def clean_dns(cls, instances, **kwargs): dnsaas = DNSaaS() # TODO: transaction? for instance in instances: - ips = list(instance.ipaddresses.exclude( - is_management=True - ).values_list('address', flat=True)) - if not ips: - logger.info( - 'No IPs for %s - skipping cleaning DNS entries', - instance + ips = list( + instance.ipaddresses.exclude(is_management=True).values_list( + "address", flat=True ) + ) + if not ips: + logger.info("No IPs for %s - skipping cleaning DNS entries", instance) continue records = dnsaas.get_dns_records(ips) if len(records) > settings.DEPLOYMENT_MAX_DNS_ENTRIES_TO_CLEAN: raise Exception( - 'Cannot clean {} entries for {} - clean it manually'.format( + "Cannot clean {} entries for {} - clean it manually".format( len(records), instance ) ) for record in records: logger.warning( - 'Deleting %s (%s / %s / %s) DNS record', - record['pk'], record['type'], record['name'], record['content'] + "Deleting %s (%s / %s / %s) DNS record", + record["pk"], + record["type"], + record["name"], + record["content"], ) - if dnsaas.delete_dns_record(record['pk']): + if dnsaas.delete_dns_record(record["pk"]): raise Exception() # TODO @deployment_action( - verbose_name=_('Clean IP addresses'), - run_after=['clean_dns'], + verbose_name=_("Clean IP addresses"), + run_after=["clean_dns"], ) def clean_ipaddresses(cls, instances, **kwargs): """ @@ -344,38 +346,38 @@ def clean_ipaddresses(cls, instances, **kwargs): """ for instance in instances: for ip in instance.ipaddresses.exclude(is_management=True): - logger.warning('Deleting %s IP address', ip) + logger.warning("Deleting %s IP address", ip) eth = ip.ethernet ip.delete() if not any([eth.mac, eth.label]): - logger.warning('Deleting %s (%s) ethernet', eth, eth.id) + logger.warning("Deleting %s (%s) ethernet", eth, eth.id) eth.delete() @deployment_action( - verbose_name=_('Clean DHCP entries'), - run_after=['clean_dns', 'clean_ipaddresses'], + verbose_name=_("Clean DHCP entries"), + run_after=["clean_dns", "clean_ipaddresses"], ) def clean_dhcp(cls, instances, **kwargs): """ Clean DHCP entries for each instance. """ for instance in instances: - _get_non_mgmt_ethernets(instance).values_list('mac', flat=True) + _get_non_mgmt_ethernets(instance).values_list("mac", flat=True) for dhcp_entry in DHCPEntry.objects.filter( ethernet__base_object=instance, dhcp_expose=True ): - logger.warning('Removing %s DHCP entry', dhcp_entry) + logger.warning("Removing %s DHCP entry", dhcp_entry) dhcp_entry.delete() @deployment_action( - verbose_name=_('Remove from DHCP entries'), + verbose_name=_("Remove from DHCP entries"), form_fields={ - 'ipaddress': { - 'field': forms.ChoiceField(label=_('DHCP Entry')), - 'choices': dhcp_entries_for_objects, - 'exclude_from_history': True, + "ipaddress": { + "field": forms.ChoiceField(label=_("DHCP Entry")), + "choices": dhcp_entries_for_objects, + "exclude_from_history": True, }, }, ) @@ -384,64 +386,63 @@ def remove_from_dhcp_entries(cls, instances, ipaddress, **kwargs): Clean DHCP entries for each instance. """ ip = IPAddress.objects.get(pk=ipaddress) - entry = '{} ({}) / {}'.format( + entry = "{} ({}) / {}".format( ip.address, ip.hostname, ip.ethernet.mac if ip.ethernet else None ) - logger.warning('Removing entry from DHCP: %s', entry) - kwargs['history_kwargs'][instances[0].pk]['DHCP entry'] = entry + logger.warning("Removing entry from DHCP: %s", entry) + kwargs["history_kwargs"][instances[0].pk]["DHCP entry"] = entry ip.dhcp_expose = False ip.save() @deployment_action( - verbose_name=_('Assign new hostname'), + verbose_name=_("Assign new hostname"), form_fields={ - 'network_environment': { - 'field': ChoiceFieldWithOtherOption( - label=_('Hostname'), + "network_environment": { + "field": ChoiceFieldWithOtherOption( + label=_("Hostname"), other_field=forms.CharField(), auto_other_choice=False, ), - 'choices': next_free_hostname_choices, - 'exclude_from_history': True, + "choices": next_free_hostname_choices, + "exclude_from_history": True, }, }, - run_after=['clean_dns', 'clean_dhcp', 'clean_hostname'], + run_after=["clean_dns", "clean_dhcp", "clean_hostname"], ) def assign_new_hostname(cls, instances, network_environment, **kwargs): """ Assign new hostname for each instance based on selected network environment. """ + def _assign_hostname(instance, new_hostname, net_env=None): - logger.info('Assigning {} to {}'.format(new_hostname, instance)) + logger.info("Assigning {} to {}".format(new_hostname, instance)) instance.hostname = new_hostname instance.save() - kwargs['history_kwargs'][instance.pk]['hostname'] = '{}{}'.format( - new_hostname, ' (from {})'.format(net_env) if net_env else '' + kwargs["history_kwargs"][instance.pk]["hostname"] = "{}{}".format( + new_hostname, " (from {})".format(net_env) if net_env else "" ) - kwargs['shared_params']['hostnames'][instance.pk] = new_hostname + kwargs["shared_params"]["hostnames"][instance.pk] = new_hostname - if 'hostnames' not in kwargs['shared_params']: - kwargs['shared_params']['hostnames'] = {} + if "hostnames" not in kwargs["shared_params"]: + kwargs["shared_params"]["hostnames"] = {} - if network_environment['value'] == OTHER: + if network_environment["value"] == OTHER: hostname = network_environment[OTHER] # when OTHER value posted, there could be only one instance _assign_hostname(instances[0], hostname) else: - net_env = NetworkEnvironment.objects.get( - pk=network_environment['value'] - ) + net_env = NetworkEnvironment.objects.get(pk=network_environment["value"]) for instance in instances: new_hostname = net_env.issue_next_free_hostname() _assign_hostname(instance, new_hostname, net_env) def validate_ip_address(instances, data): - if data['ip_or_network']['value'] == OTHER: + if data["ip_or_network"]["value"] == OTHER: assert len(instances) == 1 instance = instances[0] - address = data['ip_or_network'][OTHER] + address = data["ip_or_network"][OTHER] check_ip_from_defined_network(address) check_ipaddress_unique(instance, address) @@ -457,7 +458,7 @@ def check_ipaddress_unique(instance, address): else: if ip.ethernet and ip.ethernet.base_object_id != instance.pk: raise ValidationError( - 'IP {} is already assigned to other object!'.format(address) + "IP {} is already assigned to other object!".format(address) ) @@ -466,38 +467,32 @@ def check_ip_from_defined_network(address): Validate if `address` belongs to any network already added """ ip = ipaddress.ip_address(address) - if not Network.objects.filter( - min_ip__lte=int(ip), max_ip__gte=int(ip) - ): - raise ValidationError( - 'IP {} doesn\'t belong to any network!'.format(address) - ) + if not Network.objects.filter(min_ip__lte=int(ip), max_ip__gte=int(ip)): + raise ValidationError("IP {} doesn't belong to any network!".format(address)) @deployment_action( - verbose_name=_('Assign new IP'), + verbose_name=_("Assign new IP"), form_fields={ - 'network': { - 'field': forms.ChoiceField( - label=_('IP Address') - ), - 'choices': next_free_ip_choices, - 'exclude_from_history': True + "network": { + "field": forms.ChoiceField(label=_("IP Address")), + "choices": next_free_ip_choices, + "exclude_from_history": True, }, }, - run_after=['assign_new_hostname'], + run_after=["assign_new_hostname"], ) def assign_new_ip(cls, instances, network, **kwargs): for instance in instances: network = Network.objects.get(pk=network) ip = network.issue_next_free_ip() - logger.info('Assigning {} to {}'.format(ip, instance)) + logger.info("Assigning {} to {}".format(ip, instance)) ethernet = Ethernet.objects.create(base_object=instance) - logger.info('Bounding {} to {} ethernet'.format(ip, ethernet)) + logger.info("Bounding {} to {} ethernet".format(ip, ethernet)) ip.ethernet = ethernet try: - hostname = kwargs['shared_params']['hostnames'].get(instance.pk) + hostname = kwargs["shared_params"]["hostnames"].get(instance.pk) if hostname: ip.hostname = hostname except KeyError: @@ -510,9 +505,7 @@ def base_object_ip_choices(actions, objects): ipaddresses = [] for instance in objects: for ip in instance.ipaddresses: - ipaddresses.append( - [ip.id, '{} - {}'.format(ip.address, ip.hostname)] - ) + ipaddresses.append([ip.id, "{} - {}".format(ip.address, ip.hostname)]) return ipaddresses @@ -520,9 +513,7 @@ def base_object_network_choices(actions, objects): networks = [] for instance in objects: for network in instance._get_available_networks(): - networks.append( - [network.id, network] - ) + networks.append([network.id, network]) return networks @@ -537,95 +528,92 @@ def check_number_of_instance(instances, **kwargs): """ errors = {} if len(instances) > 1: - errors[instances[0]] = _('You can choose only one asset') + errors[instances[0]] = _("You can choose only one asset") return errors @deployment_action( - verbose_name=_('Replace IP'), + verbose_name=_("Replace IP"), form_fields={ - 'ipaddress': { - 'field': forms.ChoiceField( - label=_('IP Address'), + "ipaddress": { + "field": forms.ChoiceField( + label=_("IP Address"), ), - 'choices': base_object_ip_choices, - 'exclude_from_history': True, + "choices": base_object_ip_choices, + "exclude_from_history": True, }, - 'network': { - 'field': forms.ChoiceField( - label=_('Network'), + "network": { + "field": forms.ChoiceField( + label=_("Network"), ), - 'choices': base_object_network_choices, - 'exclude_from_history': True, + "choices": base_object_network_choices, + "exclude_from_history": True, }, }, - precondition=check_number_of_instance + precondition=check_number_of_instance, ) def replace_ip(cls, instances, ipaddress, network, **kwargs): ip = IPAddress.objects.get(pk=ipaddress) network = Network.objects.get(pk=network) new_ip_address = str(network.get_first_free_ip()) - logger.info( - 'Replacing IP {} to {}'.format(ip.address, new_ip_address) - ) + logger.info("Replacing IP {} to {}".format(ip.address, new_ip_address)) ip.address = new_ip_address ip.save() @deployment_action( - verbose_name=_('Assign new IP address and create DHCP entries'), + verbose_name=_("Assign new IP address and create DHCP entries"), form_fields={ - 'ip_or_network': { - 'field': ChoiceFieldWithOtherOption( - label=_('IP Address'), + "ip_or_network": { + "field": ChoiceFieldWithOtherOption( + label=_("IP Address"), other_field=forms.GenericIPAddressField(), - auto_other_choice=False + auto_other_choice=False, ), - 'choices': next_free_ip_choices_wth_other_choice, - 'exclude_from_history': True, - 'validation': validate_ip_address, + "choices": next_free_ip_choices_wth_other_choice, + "exclude_from_history": True, + "validation": validate_ip_address, }, - 'ethernet': { - 'field': forms.ChoiceField(label=_('MAC Address')), - 'choices': mac_choices_for_objects, - 'exclude_from_history': True, # TODO: history + "ethernet": { + "field": forms.ChoiceField(label=_("MAC Address")), + "choices": mac_choices_for_objects, + "exclude_from_history": True, # TODO: history }, }, - run_after=['assign_new_hostname', 'clean_ipaddresses', 'clean_dhcp'], - precondition=check_mac_address + run_after=["assign_new_hostname", "clean_ipaddresses", "clean_dhcp"], + precondition=check_mac_address, ) def create_dhcp_entries(cls, instances, ip_or_network, ethernet, **kwargs): """ Assign next free IP to each instance and create DHCP entries for it. """ + def _store_history(instance, ip, etherhet): - kwargs['history_kwargs'][instance.pk].update({ - 'ip': ip.address, - 'mac': etherhet.mac, - }) + kwargs["history_kwargs"][instance.pk].update( + { + "ip": ip.address, + "mac": etherhet.mac, + } + ) + if len(instances) == 1: ip, ethernet = _create_dhcp_entries_for_single_instance( instances[0], ip_or_network, ethernet ) _store_history(instances[0], ip, ethernet) - kwargs['shared_params']['ip_addresses'][instances[0].pk] = ip + kwargs["shared_params"]["ip_addresses"][instances[0].pk] = ip else: for instance, (ip, ethernet) in zip( - _create_dhcp_entries_for_many_instances( - instances, ip_or_network - ), - instances + _create_dhcp_entries_for_many_instances(instances, ip_or_network), instances ): _store_history(instance, ip, ethernet) - kwargs['shared_params']['ip_addresses'][instance.pk] = ip + kwargs["shared_params"]["ip_addresses"][instance.pk] = ip - kwargs['shared_params']['dhcp_entry_created_date'] = datetime.now() + kwargs["shared_params"]["dhcp_entry_created_date"] = datetime.now() -def _create_dhcp_entries_for_single_instance( - instance, ip_or_network, ethernet_id -): +def _create_dhcp_entries_for_single_instance(instance, ip_or_network, ethernet_id): """ Assign IP and create DHCP entries for single instance. @@ -638,20 +626,18 @@ def _create_dhcp_entries_for_single_instance( Returns: tuple with (new IP, ethernet component) """ - if ip_or_network['value'] == OTHER: + if ip_or_network["value"] == OTHER: ip_address = ip_or_network[OTHER] ip = IPAddress.objects.create(address=ip_address) else: - network = Network.objects.get( - pk=ip_or_network['value'] - ) + network = Network.objects.get(pk=ip_or_network["value"]) ip = network.issue_next_free_ip() - logger.info('Assigning {} to {}'.format(ip, instance)) + logger.info("Assigning {} to {}".format(ip, instance)) # pass base_object as param to make sure that this ethernet is assigned # to currently transitioned instance ethernet = Ethernet.objects.get(pk=ethernet_id, base_object=instance) ip.hostname = instance.hostname - logger.info('Bounding {} to {} ethernet'.format(ip, ethernet)) + logger.info("Bounding {} to {} ethernet".format(ip, ethernet)) ip.ethernet = ethernet ip.dhcp_expose = True ip.save() @@ -665,35 +651,35 @@ def _create_dhcp_entries_for_many_instances(instances, ip_or_network): for instance in instances: # when IP is assigned to many instances, mac is not provided through # form and first non-mgmt mac should be used - ethernet = _get_non_mgmt_ethernets(instance).values_list( - 'id', flat=True - ).first() # TODO: is first the best choice here? + ethernet = ( + _get_non_mgmt_ethernets(instance).values_list("id", flat=True).first() + ) # TODO: is first the best choice here? yield _create_dhcp_entries_for_single_instance( instance, ip_or_network, ethernet ) @deployment_action( - verbose_name=_('Wait for DHCP servers'), + verbose_name=_("Wait for DHCP servers"), is_async=True, - run_after=['create_dhcp_entries'], - precondition=check_if_network_environment_exists + run_after=["create_dhcp_entries"], + precondition=check_if_network_environment_exists, ) def wait_for_dhcp_servers(cls, instances, **kwargs): """ Wait until DHCP servers ping to Ralph. """ - created = kwargs['shared_params']['dhcp_entry_created_date'] + created = kwargs["shared_params"]["dhcp_entry_created_date"] # TODO: rescheduler instead of while network_environment_ids = [] - for ip in kwargs['shared_params']['ip_addresses'].values(): + for ip in kwargs["shared_params"]["ip_addresses"].values(): network_environment_ids.append(ip.network.network_environment_id) while True: servers_sync_list = DHCPServer.objects.filter( - Q(network_environment__isnull=True) | - Q(network_environment_id__in=network_environment_ids) - ).values_list('last_synchronized', flat=True) + Q(network_environment__isnull=True) + | Q(network_environment_id__in=network_environment_ids) + ).values_list("last_synchronized", flat=True) for server_sync_date in servers_sync_list: if created < server_sync_date: return @@ -701,10 +687,8 @@ def wait_for_dhcp_servers(cls, instances, **kwargs): @deployment_action( - verbose_name=_('Create DNS entries'), - run_after=[ - 'assign_new_hostname', 'create_dhcp_entries' - ], + verbose_name=_("Create DNS entries"), + run_after=["assign_new_hostname", "create_dhcp_entries"], ) def create_dns_entries(cls, instances, **kwargs): if not settings.ENABLE_DNSAAS_INTEGRATION: @@ -713,28 +697,28 @@ def create_dns_entries(cls, instances, **kwargs): # TODO: transaction? for instance in instances: # TODO: use dedicated param instead of history_kwargs - ip = kwargs['history_kwargs'][instance.pk]['ip'] + ip = kwargs["history_kwargs"][instance.pk]["ip"] dnsaas.create_dns_record( record={ - 'name': instance.hostname, - 'type': RecordType.a.id, - 'content': ip, - 'ptr': True, + "name": instance.hostname, + "type": RecordType.a.id, + "content": ip, + "ptr": True, }, - service=instance.service + service=instance.service, ) @deployment_action( - verbose_name=_('Change service-env'), + verbose_name=_("Change service-env"), form_fields={ - 'service_env': { - 'field': forms.CharField(label=_('Service-environment')), - 'autocomplete_field': 'service_env', - 'default_value': autocomplete_service_env + "service_env": { + "field": forms.CharField(label=_("Service-environment")), + "autocomplete_field": "service_env", + "default_value": autocomplete_service_env, }, }, - run_after=['clean_dns', 'clean_dhcp'], + run_after=["clean_dns", "clean_dhcp"], ) def assign_service_env(cls, instances, service_env, **kwargs): """ @@ -746,25 +730,26 @@ def assign_service_env(cls, instances, service_env, **kwargs): @deployment_action( - verbose_name=_('Change configuration_path'), + verbose_name=_("Change configuration_path"), form_fields={ - 'configuration_path': { - 'field': forms.CharField(label=_('Configuration path')), - 'autocomplete_field': 'configuration_path', - 'default_value': autocomplete_configuration_path + "configuration_path": { + "field": forms.CharField(label=_("Configuration path")), + "autocomplete_field": "configuration_path", + "default_value": autocomplete_configuration_path, }, }, - run_after=['clean_dns', 'clean_dhcp'], + run_after=["clean_dns", "clean_dhcp"], ) def assign_configuration_path(cls, instances, configuration_path, **kwargs): """ Assign configuration path to each instance. """ for instance in instances: - logger.info('Assinging {} configuration path to {}'.format( - ConfigurationClass.objects.get(pk=configuration_path), - instance - )) + logger.info( + "Assinging {} configuration path to {}".format( + ConfigurationClass.objects.get(pk=configuration_path), instance + ) + ) instance.configuration_path_id = configuration_path instance.save() @@ -785,24 +770,23 @@ def get_preboot_choices(actions, objects): @deployment_action( - verbose_name=_('Apply preboot'), + verbose_name=_("Apply preboot"), form_fields={ - 'preboot': { - 'field': forms.ChoiceField( - label=_('Preboot'), - widget=forms.Select( - attrs={"id": "preboot-select"} - ) + "preboot": { + "field": forms.ChoiceField( + label=_("Preboot"), widget=forms.Select(attrs={"id": "preboot-select"}) ), - 'choices': get_preboot_choices, + "choices": get_preboot_choices, } }, is_async=True, run_after=[ - 'assign_new_hostname', 'create_dhcp_entries', 'wait_for_dhcp_servers', - 'create_dns_entries', + "assign_new_hostname", + "create_dhcp_entries", + "wait_for_dhcp_servers", + "create_dns_entries", ], - precondition=check_if_deployment_is_available + precondition=check_if_deployment_is_available, ) def deploy(cls, instances, **kwargs): """ @@ -813,9 +797,9 @@ def deploy(cls, instances, **kwargs): @deployment_action( - verbose_name=_('Wait for ping'), + verbose_name=_("Wait for ping"), is_async=True, - run_after=['deploy'], + run_after=["deploy"], ) def wait_for_ping(cls, instances, tja, **kwargs): """ diff --git a/src/ralph/deployment/forms.py b/src/ralph/deployment/forms.py index 5ec88fcaa3..54713c5622 100644 --- a/src/ralph/deployment/forms.py +++ b/src/ralph/deployment/forms.py @@ -12,38 +12,38 @@ class PrebootConfigurationForm(RalphAdminFormMixin, forms.ModelForm): class Meta: model = PrebootConfiguration - fields = ('name', 'type', 'configuration') + fields = ("name", "type", "configuration") def is_valid(self): is_valid = super().is_valid() try: configuration = _render_configuration( - self.cleaned_data.get('configuration', ''), MagicMock(), - disable_reverse=True + self.cleaned_data.get("configuration", ""), + MagicMock(), + disable_reverse=True, ) except TemplateSyntaxError as error: - self.add_error('configuration', error) + self.add_error("configuration", error) return False - configuration_type = self.cleaned_data.get('type') - if configuration_type in ( - PrebootItemType.meta_data, PrebootItemType.user_data - ): + configuration_type = self.cleaned_data.get("type") + if configuration_type in (PrebootItemType.meta_data, PrebootItemType.user_data): try: yaml.load(configuration, Loader=yaml.FullLoader) except yaml.YAMLError as error: - self.add_error('configuration', error) + self.add_error("configuration", error) return False return is_valid def clean_configuration(self): - configuration_type = self.cleaned_data.get('type') - configuration = self.cleaned_data.get('configuration') + configuration_type = self.cleaned_data.get("type") + configuration = self.cleaned_data.get("configuration") if configuration_type in ( - PrebootItemType.kickstart.id, PrebootItemType.preseed.id, + PrebootItemType.kickstart.id, + PrebootItemType.preseed.id, PrebootItemType.user_data.id, ): - if 'done_url' not in configuration: + if "done_url" not in configuration: raise forms.ValidationError( - 'Please specify {{ done_url }} (e.g. curl {{ done_url }})' + "Please specify {{ done_url }} (e.g. curl {{ done_url }})" ) return configuration diff --git a/src/ralph/deployment/migrations/0001_initial.py b/src/ralph/deployment/migrations/0001_initial.py index dae0857f99..2d96bbd91c 100644 --- a/src/ralph/deployment/migrations/0001_initial.py +++ b/src/ralph/deployment/migrations/0001_initial.py @@ -7,82 +7,172 @@ class Migration(migrations.Migration): - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('transitions', '0005_auto_20160606_1420'), + ("contenttypes", "0002_remove_content_type_name"), + ("transitions", "0005_auto_20160606_1420"), ] operations = [ migrations.CreateModel( - name='Preboot', + name="Preboot", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)), - ('name', models.CharField(unique=True, max_length=255, verbose_name='name')), - ('description', models.TextField(blank=True, verbose_name='description', default='')), - ('used_counter', models.PositiveIntegerField(editable=False, default=0)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(unique=True, max_length=255, verbose_name="name"), + ), + ( + "description", + models.TextField( + blank=True, verbose_name="description", default="" + ), + ), + ( + "used_counter", + models.PositiveIntegerField(editable=False, default=0), + ), ], options={ - 'verbose_name': 'preboot', - 'verbose_name_plural': 'preboots', - 'ordering': ('name',), + "verbose_name": "preboot", + "verbose_name_plural": "preboots", + "ordering": ("name",), }, ), migrations.CreateModel( - name='PrebootItem', + name="PrebootItem", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)), - ('name', models.CharField(unique=True, max_length=255, verbose_name='name')), - ('description', models.TextField(blank=True, verbose_name='description', default='')), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(unique=True, max_length=255, verbose_name="name"), + ), + ( + "description", + models.TextField( + blank=True, verbose_name="description", default="" + ), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, ), migrations.CreateModel( - name='Deployment', - fields=[ - ], + name="Deployment", + fields=[], options={ - 'proxy': True, + "proxy": True, }, - bases=('transitions.transitionjob',), + bases=("transitions.transitionjob",), ), migrations.CreateModel( - name='PrebootConfiguration', + name="PrebootConfiguration", fields=[ - ('prebootitem_ptr', models.OneToOneField(serialize=False, primary_key=True, to='deployment.PrebootItem', parent_link=True, auto_created=True, on_delete=django.db.models.deletion.CASCADE)), - ('type', models.PositiveIntegerField(choices=[(41, 'ipxe'), (42, 'kickstart')], verbose_name='type', default=41)), - ('configuration', models.TextField(help_text='All newline characters will be converted to Unix \\n newlines. You can use {{variables}} in the body. Available variables: ralph_instance, deployment_id, kickstart, initrd, kernel, dc, done_url.', blank=True, verbose_name='configuration')), + ( + "prebootitem_ptr", + models.OneToOneField( + serialize=False, + primary_key=True, + to="deployment.PrebootItem", + parent_link=True, + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "type", + models.PositiveIntegerField( + choices=[(41, "ipxe"), (42, "kickstart")], + verbose_name="type", + default=41, + ), + ), + ( + "configuration", + models.TextField( + help_text="All newline characters will be converted to Unix \\n newlines. You can use {{variables}} in the body. Available variables: ralph_instance, deployment_id, kickstart, initrd, kernel, dc, done_url.", + blank=True, + verbose_name="configuration", + ), + ), ], options={ - 'verbose_name': 'preboot configuration', - 'verbose_name_plural': 'preboot configuration', + "verbose_name": "preboot configuration", + "verbose_name_plural": "preboot configuration", }, - bases=('deployment.prebootitem',), + bases=("deployment.prebootitem",), ), migrations.CreateModel( - name='PrebootFile', + name="PrebootFile", fields=[ - ('prebootitem_ptr', models.OneToOneField(serialize=False, primary_key=True, to='deployment.PrebootItem', parent_link=True, auto_created=True, on_delete=django.db.models.deletion.CASCADE)), - ('type', models.PositiveIntegerField(choices=[(1, 'kernel'), (2, 'initrd')], verbose_name='type', default=1)), - ('file', models.FileField(upload_to=ralph.deployment.models.preboot_file_name, null=True, verbose_name='file', default=None, blank=True)), + ( + "prebootitem_ptr", + models.OneToOneField( + serialize=False, + primary_key=True, + to="deployment.PrebootItem", + parent_link=True, + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "type", + models.PositiveIntegerField( + choices=[(1, "kernel"), (2, "initrd")], + verbose_name="type", + default=1, + ), + ), + ( + "file", + models.FileField( + upload_to=ralph.deployment.models.preboot_file_name, + null=True, + verbose_name="file", + default=None, + blank=True, + ), + ), ], options={ - 'verbose_name': 'preboot file', - 'verbose_name_plural': 'preboot files', + "verbose_name": "preboot file", + "verbose_name_plural": "preboot files", }, - bases=('deployment.prebootitem',), + bases=("deployment.prebootitem",), ), migrations.AddField( - model_name='prebootitem', - name='content_type', - field=models.ForeignKey(to='contenttypes.ContentType', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="prebootitem", + name="content_type", + field=models.ForeignKey( + to="contenttypes.ContentType", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='preboot', - name='items', - field=models.ManyToManyField(blank=True, verbose_name='files', to='deployment.PrebootItem'), + model_name="preboot", + name="items", + field=models.ManyToManyField( + blank=True, verbose_name="files", to="deployment.PrebootItem" + ), ), ] diff --git a/src/ralph/deployment/migrations/0002_auto_20160816_1112.py b/src/ralph/deployment/migrations/0002_auto_20160816_1112.py index e566df409f..b5f64204cd 100644 --- a/src/ralph/deployment/migrations/0002_auto_20160816_1112.py +++ b/src/ralph/deployment/migrations/0002_auto_20160816_1112.py @@ -5,15 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0001_initial'), + ("deployment", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='prebootconfiguration', - name='configuration', - field=models.TextField(blank=True, help_text="All newline characters will be converted to Unix \\n newlines.\n
    You can use {{variables}} in the body.\n
    Available variables:\n\n
    - configuration_class_name (eg. 'www')\n
    - configuration_module (eg. 'ralph')\n
    - configuration_path (eg. 'ralph/www')\n
    - dc (eg. 'data-center1')\n
    - deployment_id (eg. 'ea9ea3a0-1c4d-42b7-a19b-922000abe9f7')\n
    - domain (eg. 'dc1.mydc.net')\n
    - done_url (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/mark_as_done')\n
    - hostname (eg. 'ralph123.dc1.mydc.net')\n
    - initrd (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/initrd')\n
    - kernel (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kernel')\n
    - kickstart (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kickstart')\n
    - ralph_instance (eg. 'http://127.0.0.1:8000')\n
    - service_env (eg. 'Backup systems - prod')\n
    - service_uid (eg. 'sc-123')", verbose_name='configuration'), + model_name="prebootconfiguration", + name="configuration", + field=models.TextField( + blank=True, + help_text="All newline characters will be converted to Unix \\n newlines.\n
    You can use {{variables}} in the body.\n
    Available variables:\n\n
    - configuration_class_name (eg. 'www')\n
    - configuration_module (eg. 'ralph')\n
    - configuration_path (eg. 'ralph/www')\n
    - dc (eg. 'data-center1')\n
    - deployment_id (eg. 'ea9ea3a0-1c4d-42b7-a19b-922000abe9f7')\n
    - domain (eg. 'dc1.mydc.net')\n
    - done_url (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/mark_as_done')\n
    - hostname (eg. 'ralph123.dc1.mydc.net')\n
    - initrd (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/initrd')\n
    - kernel (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kernel')\n
    - kickstart (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kickstart')\n
    - ralph_instance (eg. 'http://127.0.0.1:8000')\n
    - service_env (eg. 'Backup systems - prod')\n
    - service_uid (eg. 'sc-123')", + verbose_name="configuration", + ), ), ] diff --git a/src/ralph/deployment/migrations/0003_auto_20161124_1317.py b/src/ralph/deployment/migrations/0003_auto_20161124_1317.py index 14d4b02dc5..355478c405 100644 --- a/src/ralph/deployment/migrations/0003_auto_20161124_1317.py +++ b/src/ralph/deployment/migrations/0003_auto_20161124_1317.py @@ -5,20 +5,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0002_auto_20160816_1112'), + ("deployment", "0002_auto_20160816_1112"), ] operations = [ migrations.AlterField( - model_name='prebootconfiguration', - name='configuration', - field=models.TextField(verbose_name='configuration', blank=True, help_text="All newline characters will be converted to Unix \\n newlines.\n
    You can use {{variables}} in the body.\n
    Available variables:\n\n
    - configuration_class_name (eg. 'www')\n
    - configuration_module (eg. 'ralph')\n
    - configuration_path (eg. 'ralph/www')\n
    - dc (eg. 'data-center1')\n
    - deployment_id (eg. 'ea9ea3a0-1c4d-42b7-a19b-922000abe9f7')\n
    - domain (eg. 'dc1.mydc.net')\n
    - done_url (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/mark_as_done')\n
    - hostname (eg. 'ralph123.dc1.mydc.net')\n
    - initrd (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/initrd')\n
    - kernel (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kernel')\n
    - netboot (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/netboot')\n
    - kickstart (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kickstart')\n
    - ralph_instance (eg. 'http://127.0.0.1:8000')\n
    - service_env (eg. 'Backup systems - prod')\n
    - service_uid (eg. 'sc-123')"), + model_name="prebootconfiguration", + name="configuration", + field=models.TextField( + verbose_name="configuration", + blank=True, + help_text="All newline characters will be converted to Unix \\n newlines.\n
    You can use {{variables}} in the body.\n
    Available variables:\n\n
    - configuration_class_name (eg. 'www')\n
    - configuration_module (eg. 'ralph')\n
    - configuration_path (eg. 'ralph/www')\n
    - dc (eg. 'data-center1')\n
    - deployment_id (eg. 'ea9ea3a0-1c4d-42b7-a19b-922000abe9f7')\n
    - domain (eg. 'dc1.mydc.net')\n
    - done_url (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/mark_as_done')\n
    - hostname (eg. 'ralph123.dc1.mydc.net')\n
    - initrd (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/initrd')\n
    - kernel (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kernel')\n
    - netboot (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/netboot')\n
    - kickstart (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kickstart')\n
    - ralph_instance (eg. 'http://127.0.0.1:8000')\n
    - service_env (eg. 'Backup systems - prod')\n
    - service_uid (eg. 'sc-123')", + ), ), migrations.AlterField( - model_name='prebootfile', - name='type', - field=models.PositiveIntegerField(choices=[(1, 'kernel'), (2, 'initrd'), (3, 'netboot')], verbose_name='type', default=1), + model_name="prebootfile", + name="type", + field=models.PositiveIntegerField( + choices=[(1, "kernel"), (2, "initrd"), (3, "netboot")], + verbose_name="type", + default=1, + ), ), ] diff --git a/src/ralph/deployment/migrations/0004_auto_20161128_1359.py b/src/ralph/deployment/migrations/0004_auto_20161128_1359.py index 6bc099da0b..2883912769 100644 --- a/src/ralph/deployment/migrations/0004_auto_20161128_1359.py +++ b/src/ralph/deployment/migrations/0004_auto_20161128_1359.py @@ -5,20 +5,32 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0003_auto_20161124_1317'), + ("deployment", "0003_auto_20161124_1317"), ] operations = [ migrations.AlterField( - model_name='prebootconfiguration', - name='configuration', - field=models.TextField(blank=True, verbose_name='configuration', help_text="All newline characters will be converted to Unix \\n newlines.\n
    You can use {{variables}} in the body.\n
    Available variables:\n\n
    - configuration_class_name (eg. 'www')\n
    - configuration_module (eg. 'ralph')\n
    - configuration_path (eg. 'ralph/www')\n
    - dc (eg. 'data-center1')\n
    - deployment_id (eg. 'ea9ea3a0-1c4d-42b7-a19b-922000abe9f7')\n
    - domain (eg. 'dc1.mydc.net')\n
    - done_url (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/mark_as_done')\n
    - hostname (eg. 'ralph123.dc1.mydc.net')\n
    - initrd (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/initrd')\n
    - kernel (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kernel')\n
    - netboot (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/netboot')\n
    - kickstart (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kickstart')\n
    - preseed (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/preseed')\n
    - script (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/script')\n
    - ralph_instance (eg. 'http://127.0.0.1:8000')\n
    - service_env (eg. 'Backup systems - prod')\n
    - service_uid (eg. 'sc-123')"), + model_name="prebootconfiguration", + name="configuration", + field=models.TextField( + blank=True, + verbose_name="configuration", + help_text="All newline characters will be converted to Unix \\n newlines.\n
    You can use {{variables}} in the body.\n
    Available variables:\n\n
    - configuration_class_name (eg. 'www')\n
    - configuration_module (eg. 'ralph')\n
    - configuration_path (eg. 'ralph/www')\n
    - dc (eg. 'data-center1')\n
    - deployment_id (eg. 'ea9ea3a0-1c4d-42b7-a19b-922000abe9f7')\n
    - domain (eg. 'dc1.mydc.net')\n
    - done_url (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/mark_as_done')\n
    - hostname (eg. 'ralph123.dc1.mydc.net')\n
    - initrd (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/initrd')\n
    - kernel (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kernel')\n
    - netboot (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/netboot')\n
    - kickstart (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/kickstart')\n
    - preseed (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/preseed')\n
    - script (eg. 'http://127.0.0.1:8000/deployment/ea9ea3a0-1c4d-42b7-a19b-922000abe9f7/script')\n
    - ralph_instance (eg. 'http://127.0.0.1:8000')\n
    - service_env (eg. 'Backup systems - prod')\n
    - service_uid (eg. 'sc-123')", + ), ), migrations.AlterField( - model_name='prebootconfiguration', - name='type', - field=models.PositiveIntegerField(default=41, verbose_name='type', choices=[(41, 'ipxe'), (42, 'kickstart'), (43, 'preseed'), (44, 'script')]), + model_name="prebootconfiguration", + name="type", + field=models.PositiveIntegerField( + default=41, + verbose_name="type", + choices=[ + (41, "ipxe"), + (42, "kickstart"), + (43, "preseed"), + (44, "script"), + ], + ), ), ] diff --git a/src/ralph/deployment/migrations/0005_auto_20180625_1257.py b/src/ralph/deployment/migrations/0005_auto_20180625_1257.py index ef33f55fb0..dc83076cbb 100644 --- a/src/ralph/deployment/migrations/0005_auto_20180625_1257.py +++ b/src/ralph/deployment/migrations/0005_auto_20180625_1257.py @@ -6,15 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0004_auto_20161128_1359'), + ("deployment", "0004_auto_20161128_1359"), ] operations = [ migrations.AlterField( - model_name='prebootconfiguration', - name='configuration', - field=ralph.lib.mixins.fields.NUMP(models.TextField(blank=True), fields_to_ignore=('help_text', 'verbose_name')), + model_name="prebootconfiguration", + name="configuration", + field=ralph.lib.mixins.fields.NUMP( + models.TextField(blank=True), + fields_to_ignore=("help_text", "verbose_name"), + ), ), ] diff --git a/src/ralph/deployment/migrations/0006_auto_20211019_1456.py b/src/ralph/deployment/migrations/0006_auto_20211019_1456.py index 132e42c082..bf1c1f9cb7 100644 --- a/src/ralph/deployment/migrations/0006_auto_20211019_1456.py +++ b/src/ralph/deployment/migrations/0006_auto_20211019_1456.py @@ -5,15 +5,25 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0005_auto_20180625_1257'), + ("deployment", "0005_auto_20180625_1257"), ] operations = [ migrations.AlterField( - model_name='prebootconfiguration', - name='type', - field=models.PositiveIntegerField(verbose_name='type', default=41, choices=[(41, 'ipxe'), (42, 'kickstart'), (43, 'preseed'), (44, 'script'), (45, 'meta_data'), (46, 'user_data')]), + model_name="prebootconfiguration", + name="type", + field=models.PositiveIntegerField( + verbose_name="type", + default=41, + choices=[ + (41, "ipxe"), + (42, "kickstart"), + (43, "preseed"), + (44, "script"), + (45, "meta_data"), + (46, "user_data"), + ], + ), ), ] diff --git a/src/ralph/deployment/migrations/0007_auto_20240506_1633.py b/src/ralph/deployment/migrations/0007_auto_20240506_1633.py index 70a0dbeb64..0c17197fc1 100644 --- a/src/ralph/deployment/migrations/0007_auto_20240506_1633.py +++ b/src/ralph/deployment/migrations/0007_auto_20240506_1633.py @@ -7,28 +7,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0006_auto_20211019_1456'), + ("deployment", "0006_auto_20211019_1456"), ] operations = [ migrations.AlterModelManagers( - name='prebootconfiguration', + name="prebootconfiguration", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='prebootfile', + name="prebootfile", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='prebootitem', + name="prebootitem", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/deployment/migrations/0008_auto_20240705_1210.py b/src/ralph/deployment/migrations/0008_auto_20240705_1210.py index 4a06eb1474..2f9d89a6c8 100644 --- a/src/ralph/deployment/migrations/0008_auto_20240705_1210.py +++ b/src/ralph/deployment/migrations/0008_auto_20240705_1210.py @@ -4,25 +4,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0007_auto_20240506_1633'), + ("deployment", "0007_auto_20240506_1633"), ] operations = [ migrations.AddField( - model_name='preboot', - name='critical_after', + model_name="preboot", + name="critical_after", field=models.DateField(blank=False, null=True), ), migrations.AddField( - model_name='preboot', - name='disappears_after', + model_name="preboot", + name="disappears_after", field=models.DateField(blank=False, null=True), ), migrations.AddField( - model_name='preboot', - name='warning_after', + model_name="preboot", + name="warning_after", field=models.DateField(blank=False, null=True), ), ] diff --git a/src/ralph/deployment/migrations/0009_auto_20240924_1133.py b/src/ralph/deployment/migrations/0009_auto_20240924_1133.py index b8a6a61e61..56bc7fdc3a 100644 --- a/src/ralph/deployment/migrations/0009_auto_20240924_1133.py +++ b/src/ralph/deployment/migrations/0009_auto_20240924_1133.py @@ -7,15 +7,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('deployment', '0008_auto_20240705_1210'), + ("deployment", "0008_auto_20240705_1210"), ] operations = [ migrations.AlterField( - model_name='preboot', - name='items', - field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField(blank=True, to='deployment.PrebootItem', verbose_name='files'), + model_name="preboot", + name="items", + field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField( + blank=True, to="deployment.PrebootItem", verbose_name="files" + ), ), ] diff --git a/src/ralph/deployment/mixins.py b/src/ralph/deployment/mixins.py index 70ac7bb337..695e6b6f00 100644 --- a/src/ralph/deployment/mixins.py +++ b/src/ralph/deployment/mixins.py @@ -1,34 +1,29 @@ from django.contrib import messages from django.utils.safestring import mark_safe -from ralph.lib.transitions.models import ( - TransitionJob, - TransitionJobActionStatus -) +from ralph.lib.transitions.models import TransitionJob, TransitionJobActionStatus def get_actions_statuses_as_html(transition): # TODO: sort actions # TODO: verbose_name actions_to_execute = transition.transition.actions.all() - executed_actions = transition.transition_job_actions.all().order_by('created').values( # noqa - 'action_name', 'status' + executed_actions = ( + transition.transition_job_actions.all() + .order_by("created") + .values( # noqa + "action_name", "status" + ) ) def action_as_html(action): - css_class = 'queued' - job_action = [a for a in executed_actions if action.name == a['action_name']] # noqa + css_class = "queued" + job_action = [a for a in executed_actions if action.name == a["action_name"]] # noqa if job_action and len(job_action): - css_class = TransitionJobActionStatus.desc_from_id( - job_action[0]['status'] - ) - return '{}'.format( - css_class, action.name - ) - return ' '.join([ - action_as_html(a) - for a in actions_to_execute - ]) + css_class = TransitionJobActionStatus.desc_from_id(job_action[0]["status"]) + return '{}'.format(css_class, action.name) + + return " ".join([action_as_html(a) for a in actions_to_execute]) class ActiveDeploymentMessageMixin(object): @@ -36,16 +31,18 @@ def changeform_view(self, request, object_id, *args, **kwargs): current_transitions = None obj = self.get_object(request, object_id) if obj: - current_transitions = TransitionJob.get_transitions_for_object( - obj=obj - ) + current_transitions = TransitionJob.get_transitions_for_object(obj=obj) if current_transitions: current_transition = current_transitions.first() # TODO: separeted view - messages.info(request, mark_safe( - 'Transition {} is in progress. Current status of actions: {}'.format( # noqa - current_transition.transition, - get_actions_statuses_as_html(current_transition) - ) - ), extra_tags='static') + messages.info( + request, + mark_safe( + 'Transition {} is in progress. Current status of actions: {}'.format( # noqa + current_transition.transition, + get_actions_statuses_as_html(current_transition), + ) + ), + extra_tags="static", + ) return super().changeform_view(request, object_id, *args, **kwargs) diff --git a/src/ralph/deployment/models.py b/src/ralph/deployment/models.py index cd1e82e516..b2fa34bda2 100644 --- a/src/ralph/deployment/models.py +++ b/src/ralph/deployment/models.py @@ -25,49 +25,42 @@ class PrebootItemType(Choices): _ = Choices.Choice LINUX = Choices.Group(0) - kernel = _('kernel') - initrd = _('initrd') - netboot = _('netboot') + kernel = _("kernel") + initrd = _("initrd") + netboot = _("netboot") CONFIGURATION = Choices.Group(40) - ipxe = _('iPXE') - kickstart = _('kickstart') - preseed = _('preseed') - script = _('script') - meta_data = _('meta-data') - user_data = _('user-data') + ipxe = _("iPXE") + kickstart = _("kickstart") + preseed = _("preseed") + script = _("script") + meta_data = _("meta-data") + user_data = _("user-data") OTHER = Choices.Group(100) - other = _('other') + other = _("other") def get_choices_from_group(choices_group): - return ( - (choice.id, choice.name) for choice in choices_group.choices - ) + return ((choice.id, choice.name) for choice in choices_group.choices) def preboot_file_name(instance, filename): - return os.sep.join( - ('pxe', instance.get_type_display(), slugify(instance.name)) - ) + return os.sep.join(("pxe", instance.get_type_display(), slugify(instance.name))) class PrebootItem( - AdminAbsoluteUrlMixin, - NamedMixin, - Polymorphic, - metaclass=PolymorphicBase + AdminAbsoluteUrlMixin, NamedMixin, Polymorphic, metaclass=PolymorphicBase ): description = models.TextField( - verbose_name=_('description'), + verbose_name=_("description"), blank=True, - default='', + default="", ) @property def autocomplete_str(self): - return '{} {}'.format(self.get_type_display(), self.name) + return "{} {}".format(self.get_type_display(), self.name) CONFIGURATION_HELP_TEXT = """ @@ -95,39 +88,37 @@ def autocomplete_str(self):
    - ralph_instance (eg. '{ralph_instance}')
    - service_env (eg. 'Backup systems - prod')
    - service_uid (eg. 'sc-123') -""".format(ralph_instance=settings.RALPH_INSTANCE.rstrip('/')).strip() # noqa +""".format(ralph_instance=settings.RALPH_INSTANCE.rstrip("/")).strip() # noqa class PrebootConfiguration(PrebootItem): type = models.PositiveIntegerField( - verbose_name=_('type'), + verbose_name=_("type"), choices=get_choices_from_group(PrebootItemType.CONFIGURATION), default=PrebootItemType.ipxe.id, ) configuration = NUMP( models.TextField( - _('configuration'), - blank=True, - help_text=_(CONFIGURATION_HELP_TEXT) + _("configuration"), blank=True, help_text=_(CONFIGURATION_HELP_TEXT) ) ) class Meta: - verbose_name = _('preboot configuration') - verbose_name_plural = _('preboot configuration') + verbose_name = _("preboot configuration") + verbose_name_plural = _("preboot configuration") def __str__(self): - return '{} - {}'.format(self.name, self.get_type_display()) + return "{} - {}".format(self.name, self.get_type_display()) class PrebootFile(PrebootItem): type = models.PositiveIntegerField( - verbose_name=_('type'), + verbose_name=_("type"), choices=get_choices_from_group(PrebootItemType.LINUX), default=PrebootItemType.kernel.id, ) file = models.FileField( - _('file'), + _("file"), upload_to=preboot_file_name, null=True, blank=True, @@ -135,15 +126,20 @@ class PrebootFile(PrebootItem): ) class Meta: - verbose_name = _('preboot file') - verbose_name_plural = _('preboot files') + verbose_name = _("preboot file") + verbose_name_plural = _("preboot files") class ActiveObjectsManager(Manager): def get_queryset(self): - return super().get_queryset().filter( - Q(disappears_after__isnull=True) - | Q(disappears_after__gte=timezone.now())) + return ( + super() + .get_queryset() + .filter( + Q(disappears_after__isnull=True) + | Q(disappears_after__gte=timezone.now()) + ) + ) class Preboot(AdminAbsoluteUrlMixin, NamedMixin): @@ -153,12 +149,12 @@ class Preboot(AdminAbsoluteUrlMixin, NamedMixin): items = PolymorphicManyToManyField( PrebootItem, blank=True, - verbose_name=_('files'), + verbose_name=_("files"), ) description = models.TextField( - verbose_name=_('description'), + verbose_name=_("description"), blank=True, - default='', + default="", ) warning_after = models.DateField(null=True, blank=False) critical_after = models.DateField(null=True, blank=False) @@ -167,19 +163,19 @@ class Preboot(AdminAbsoluteUrlMixin, NamedMixin): used_counter = models.PositiveIntegerField(default=0, editable=False) class Meta: - verbose_name = _('preboot') - verbose_name_plural = _('preboots') - ordering = ('name',) + verbose_name = _("preboot") + verbose_name_plural = _("preboots") + ordering = ("name",) def increment_used_counter(self): - self.used_counter = F('used_counter') + 1 + self.used_counter = F("used_counter") + 1 self.save() def _get_item(self, model_name, item_type): item = None try: queryset_kwargs = { - '{}__type'.format(model_name): PrebootItemType.id_from_name(item_type) # noqa + "{}__type".format(model_name): PrebootItemType.id_from_name(item_type) # noqa } item = self.items.get(**queryset_kwargs) except PrebootItem.DoesNotExist: @@ -187,14 +183,13 @@ def _get_item(self, model_name, item_type): return item def get_file_url(self, file_type): - item = self._get_item(model_name='prebootfile', item_type=file_type) + item = self._get_item(model_name="prebootfile", item_type=file_type) if item is not None and item.file: return item.file.url def get_configuration(self, configuration_type): item = self._get_item( - model_name='prebootconfiguration', - item_type=configuration_type + model_name="prebootconfiguration", item_type=configuration_type ) if item is not None: return item.configuration @@ -203,10 +198,9 @@ def get_configuration(self, configuration_type): class DeploymentManager(Manager.from_queryset(JobQuerySet)): def get_queryset(self): from ralph.deployment.deployment import deploy + # TODO: test it - return super().get_queryset().filter( - transition__actions__name=deploy.__name__ - ) + return super().get_queryset().filter(transition__actions__name=deploy.__name__) class Deployment(AdminAbsoluteUrlMixin, TransitionJob): @@ -219,13 +213,12 @@ class Meta: def get_deployment_for_ip(cls, ip): base_object = Ethernet.objects.get(ipaddress__address=ip).base_object return cls.objects.active().get( - content_type_id=base_object.content_type_id, - object_id=base_object.id + content_type_id=base_object.content_type_id, object_id=base_object.id ) @property def preboot(self): - return self.params['data']['deploy__preboot'] + return self.params["data"]["deploy__preboot"] @classmethod def mark_as_done(cls, deployment_id): @@ -233,6 +226,4 @@ def mark_as_done(cls, deployment_id): if deployment.is_frozen: deployment.unfreeze() else: - logger.warning( - 'Deployment %s was already unfrozen', deployment - ) + logger.warning("Deployment %s was already unfrozen", deployment) diff --git a/src/ralph/deployment/tests/factories.py b/src/ralph/deployment/tests/factories.py index 2c4ee3e885..b42d560dbc 100644 --- a/src/ralph/deployment/tests/factories.py +++ b/src/ralph/deployment/tests/factories.py @@ -6,16 +6,14 @@ class PrebootFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'Preboot {}'.format(n)) + name = factory.Sequence(lambda n: "Preboot {}".format(n)) class Meta: model = Preboot class PrebootConfigurationFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'PrebootConfiguration {}'.format(n)) + name = factory.Sequence(lambda n: "PrebootConfiguration {}".format(n)) class Meta: model = PrebootConfiguration diff --git a/src/ralph/deployment/tests/test_deployment.py b/src/ralph/deployment/tests/test_deployment.py index 44fec12ff3..06398cee74 100644 --- a/src/ralph/deployment/tests/test_deployment.py +++ b/src/ralph/deployment/tests/test_deployment.py @@ -2,20 +2,16 @@ from unittest import mock from ddt import data, ddt, unpack -from django.conf import settings from django.core.exceptions import ValidationError from django.test import override_settings, TestCase from ralph.assets.models import Ethernet from ralph.assets.tests.factories import ServiceEnvironmentFactory -from ralph.data_center.tests.factories import ( - DataCenterAssetFactory, - RackFactory -) +from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory from ralph.deployment.deployment import ( autocomplete_service_env, check_if_network_environment_exists, - validate_ip_address + validate_ip_address, ) from ralph.deployment.tests.factories import _get_deployment from ralph.deployment.utils import _render_configuration @@ -24,7 +20,7 @@ from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory + NetworkFactory, ) from ralph.virtual.tests.factories import VirtualServerFactory @@ -34,106 +30,97 @@ class _BaseTestDeploymentActionsTestCase(object): def setUpClass(cls): super().setUpClass() cls._dns_record = { - 'pk': 10, - 'name': 's12345.mydc.net', - 'type': 1, - 'content': '10.20.30.40', - 'ptr': True, - 'owner': '_ralph' + "pk": 10, + "name": "s12345.mydc.net", + "type": 1, + "content": "10.20.30.40", + "ptr": True, + "owner": "_ralph", } def test_clean_hostname(self): - self.instance.hostname = 'test' + self.instance.hostname = "test" self.instance.__class__.clean_hostname([self.instance]) # TODO: needs NullableCharField fix for VirtualServer # self.assertIsNone(self.instance.hostname) @override_settings(ENABLE_DNSAAS_INTEGRATION=True) - @mock.patch('ralph.deployment.deployment.DNSaaS._get_oauth_token') - @mock.patch('ralph.deployment.deployment.DNSaaS.get_dns_records') - @mock.patch('ralph.deployment.deployment.DNSaaS.delete_dns_record') - def test_clean_dns(self, delete_dns_record_mock, get_dns_records_mock, _get_oauth_token_mock): - IPAddressFactory(address='10.20.30.41') - IPAddressFactory( - ethernet__base_object=self.instance, is_management=True - ) + @mock.patch("ralph.deployment.deployment.DNSaaS._get_oauth_token") + @mock.patch("ralph.deployment.deployment.DNSaaS.get_dns_records") + @mock.patch("ralph.deployment.deployment.DNSaaS.delete_dns_record") + def test_clean_dns( + self, delete_dns_record_mock, get_dns_records_mock, _get_oauth_token_mock + ): + IPAddressFactory(address="10.20.30.41") + IPAddressFactory(ethernet__base_object=self.instance, is_management=True) IPAddressFactory( ethernet__base_object=self.instance, ethernet__mac=None, ethernet__label=None, - address='10.20.30.40', + address="10.20.30.40", ) delete_dns_record_mock.return_value = False get_dns_records_mock.return_value = [self._dns_record] * 3 - _get_oauth_token_mock.return_value = 'token' + _get_oauth_token_mock.return_value = "token" history = {self.instance.pk: {}} - self.instance.__class__.clean_dns( - [self.instance], history_kwargs=history - ) - get_dns_records_mock.assert_called_with(['10.20.30.40']) + self.instance.__class__.clean_dns([self.instance], history_kwargs=history) + get_dns_records_mock.assert_called_with(["10.20.30.40"]) self.assertEqual(delete_dns_record_mock.call_count, 3) delete_dns_record_mock.assert_called_with(10) @override_settings(ENABLE_DNSAAS_INTEGRATION=True) - @mock.patch('ralph.deployment.deployment.DNSaaS._get_oauth_token') - @mock.patch('ralph.deployment.deployment.DNSaaS.delete_dns_record') + @mock.patch("ralph.deployment.deployment.DNSaaS._get_oauth_token") + @mock.patch("ralph.deployment.deployment.DNSaaS.delete_dns_record") def test_clean_dns_with_no_ips(self, delete_dns_record_mock, _get_oauth_token_mock): - IPAddressFactory( - ethernet__base_object=self.instance, is_management=True - ) - _get_oauth_token_mock.return_value = 'token' + IPAddressFactory(ethernet__base_object=self.instance, is_management=True) + _get_oauth_token_mock.return_value = "token" history = {self.instance.pk: {}} - self.instance.__class__.clean_dns( - [self.instance], history_kwargs=history - ) + self.instance.__class__.clean_dns([self.instance], history_kwargs=history) self.assertEqual(delete_dns_record_mock.call_count, 0) @override_settings(ENABLE_DNSAAS_INTEGRATION=True) - @mock.patch('ralph.deployment.deployment.DNSaaS._get_oauth_token') - @mock.patch('ralph.deployment.deployment.DNSaaS.get_dns_records') - def test_clean_dns_with_too_much_ips(self, get_dns_records_mock, _get_oauth_token_mock): + @mock.patch("ralph.deployment.deployment.DNSaaS._get_oauth_token") + @mock.patch("ralph.deployment.deployment.DNSaaS.get_dns_records") + def test_clean_dns_with_too_much_ips( + self, get_dns_records_mock, _get_oauth_token_mock + ): IPAddressFactory( ethernet__base_object=self.instance, ethernet__mac=None, ethernet__label=None, - address='10.20.30.40', + address="10.20.30.40", ) history = {self.instance.pk: {}} - _get_oauth_token_mock.return_value = 'token' + _get_oauth_token_mock.return_value = "token" get_dns_records_mock.return_value = [self._dns_record] * 50 history = {self.instance.pk: {}} with self.assertRaises(Exception) as e: - self.instance.__class__.clean_dns( - [self.instance], history_kwargs=history - ) + self.instance.__class__.clean_dns([self.instance], history_kwargs=history) self.assertEqual( str(e.exception), - 'Cannot clean 50 entries for {} - clean it manually'.format( - self.instance - ) + "Cannot clean 50 entries for {} - clean it manually".format(self.instance), ) def test_a_dhcp_servers_wait(self): start_date = datetime.datetime(2016, 8, 5, 1, 1, 1) end_date = datetime.datetime(2016, 8, 5, 1, 1, 2) net = Network.objects.create( - name='net', address='192.169.58.0/24', - network_environment=NetworkEnvironmentFactory() + name="net", + address="192.169.58.0/24", + network_environment=NetworkEnvironmentFactory(), ) ip = IPAddress.objects.create( - address='192.169.58.1', status=IPAddressStatus.reserved + address="192.169.58.1", status=IPAddressStatus.reserved ) DHCPServer.objects.create( - ip='10.0.0.1', + ip="10.0.0.1", network_environment=net.network_environment, - last_synchronized=end_date + last_synchronized=end_date, ) kwargs = { - 'shared_params': { - 'dhcp_entry_created_date': start_date, - 'ip_addresses': { - self.instance.pk: ip - } + "shared_params": { + "dhcp_entry_created_date": start_date, + "ip_addresses": {self.instance.pk: ip}, } } self.instance.__class__.wait_for_dhcp_servers([self.instance], **kwargs) @@ -169,144 +156,138 @@ def test_clean_dhcp(self): def _prepare_rack(self): self.rack = RackFactory() self.net_env = NetworkEnvironmentFactory( - hostname_template_prefix='server_1', - hostname_template_postfix='.mydc.net', + hostname_template_prefix="server_1", + hostname_template_postfix=".mydc.net", ) self.net = NetworkFactory( network_environment=self.net_env, - address='10.20.30.0/24', + address="10.20.30.0/24", ) self.net.racks.add(self.rack) return self.net_env def test_assign_new_hostname(self): self._prepare_rack() - next_free_hostname = 'server_10001.mydc.net' + next_free_hostname = "server_10001.mydc.net" history = {self.instance.pk: {}} self.instance.__class__.assign_new_hostname( - [self.instance], {'value': self.net_env.id}, + [self.instance], + {"value": self.net_env.id}, history_kwargs=history, - shared_params={'hostnames': {self.instance.pk: ''}} + shared_params={"hostnames": {self.instance.pk: ""}}, ) self.assertEqual(self.instance.hostname, next_free_hostname) - self.assertEqual(history, { - self.instance.pk: { - 'hostname': '{} (from {})'.format( - next_free_hostname, self.net_env - ) - } - }) + self.assertEqual( + history, + { + self.instance.pk: { + "hostname": "{} (from {})".format(next_free_hostname, self.net_env) + } + }, + ) def test_assign_new_hostname_custom_value(self): self._prepare_rack() history = {self.instance.pk: {}} self.instance.__class__.assign_new_hostname( [self.instance], - {'value': '__other__', '__other__': 's12345.mydc.net'}, + {"value": "__other__", "__other__": "s12345.mydc.net"}, history_kwargs=history, - shared_params={'hostnames': {self.instance.pk: ''}} + shared_params={"hostnames": {self.instance.pk: ""}}, + ) + self.assertEqual(self.instance.hostname, "s12345.mydc.net") + self.assertEqual( + history, {self.instance.pk: {"hostname": "{}".format("s12345.mydc.net")}} ) - self.assertEqual(self.instance.hostname, 's12345.mydc.net') - self.assertEqual(history, { - self.instance.pk: {'hostname': '{}'.format('s12345.mydc.net')} - }) def test_remove_entry_from_dhcp(self): history = {self.instance.pk: {}} ip = IPAddressFactory( - address='10.20.30.40', - hostname='s1234.mydc.net', - ethernet__mac='aa:bb:cc:dd:ee:ff', + address="10.20.30.40", + hostname="s1234.mydc.net", + ethernet__mac="aa:bb:cc:dd:ee:ff", ethernet__base_object=self.instance, - dhcp_expose=True + dhcp_expose=True, ) self.instance.__class__.remove_from_dhcp_entries( - [self.instance], - ipaddress=ip.id, - history_kwargs=history + [self.instance], ipaddress=ip.id, history_kwargs=history ) ip.refresh_from_db() self.assertFalse(ip.dhcp_expose) - self.assertEqual(history, { - self.instance.pk: { - 'DHCP entry': '10.20.30.40 (s1234.mydc.net) / AA:BB:CC:DD:EE:FF' - } - }) + self.assertEqual( + history, + { + self.instance.pk: { + "DHCP entry": "10.20.30.40 (s1234.mydc.net) / AA:BB:CC:DD:EE:FF" + } + }, + ) @override_settings(ENABLE_DNSAAS_INTEGRATION=True) - @override_settings(DNSAAS_URL='https://dnsaas.mydc.net') - @mock.patch('ralph.deployment.deployment.DNSaaS._get_oauth_token') - @mock.patch('ralph.dns.dnsaas.DNSaaS._post') + @override_settings(DNSAAS_URL="https://dnsaas.mydc.net") + @mock.patch("ralph.deployment.deployment.DNSaaS._get_oauth_token") + @mock.patch("ralph.dns.dnsaas.DNSaaS._post") def test_create_dns_records(self, _post, _get_oauth_token_mock): - _get_oauth_token_mock.return_value = 'token' - history = {self.instance.pk: {'ip': '10.20.30.40'}} - self.instance.hostname = 's12345.mydc.net' + _get_oauth_token_mock.return_value = "token" + history = {self.instance.pk: {"ip": "10.20.30.40"}} + self.instance.hostname = "s12345.mydc.net" self.instance.__class__.create_dns_entries( - [self.instance], - history_kwargs=history + [self.instance], history_kwargs=history ) _post.assert_called_once_with( - 'https://dnsaas.mydc.net/api/records/', + "https://dnsaas.mydc.net/api/records/", { - 'type': 'A', - 'name': 's12345.mydc.net', - 'content': '10.20.30.40', - 'service_uid': self.instance.service.uid - } + "type": "A", + "name": "s12345.mydc.net", + "content": "10.20.30.40", + "service_uid": self.instance.service.uid, + }, ) - def test_check_ipaddress_unique_with_occupied_ip_should_raise_validation_error(self): # noqa - IPAddressFactory(address='10.20.30.40') + def test_check_ipaddress_unique_with_occupied_ip_should_raise_validation_error( + self, + ): # noqa + IPAddressFactory(address="10.20.30.40") with self.assertRaises(ValidationError): validate_ip_address( - [self.instance], {'ip_or_network': { - 'value': '__other__', '__other__': '10.20.30.40' - }} + [self.instance], + {"ip_or_network": {"value": "__other__", "__other__": "10.20.30.40"}}, ) - def test_check_ipaddress_unique_with_ip_assigned_to_the_same_object_should_pass(self): - NetworkFactory(address='10.20.30.0/24') - IPAddressFactory( - address='10.20.30.40', ethernet__base_object=self.instance - ) + def test_check_ipaddress_unique_with_ip_assigned_to_the_same_object_should_pass( + self, + ): + NetworkFactory(address="10.20.30.0/24") + IPAddressFactory(address="10.20.30.40", ethernet__base_object=self.instance) validate_ip_address( - [self.instance], {'ip_or_network': { - 'value': '__other__', '__other__': '10.20.30.40' - }} + [self.instance], + {"ip_or_network": {"value": "__other__", "__other__": "10.20.30.40"}}, ) def test_ip_inside_defined_network_should_pass(self): - NetworkFactory(address='10.20.30.0/24') - IPAddressFactory( - address='10.20.30.40', ethernet__base_object=self.instance - ) + NetworkFactory(address="10.20.30.0/24") + IPAddressFactory(address="10.20.30.40", ethernet__base_object=self.instance) validate_ip_address( - [self.instance], {'ip_or_network': { - 'value': '__other__', '__other__': '10.20.30.40' - }} + [self.instance], + {"ip_or_network": {"value": "__other__", "__other__": "10.20.30.40"}}, ) def test_ip_outside_defined_networks_raise_validation_error(self): - IPAddressFactory( - address='10.20.30.40', ethernet__base_object=self.instance - ) + IPAddressFactory(address="10.20.30.40", ethernet__base_object=self.instance) with self.assertRaises(ValidationError): validate_ip_address( - [self.instance], {'ip_or_network': { - 'value': '__other__', '__other__': '10.20.30.40' - }} + [self.instance], + {"ip_or_network": {"value": "__other__", "__other__": "10.20.30.40"}}, ) def test_instance_is_in_any_network_env_should_pass(self): self._prepare_rack() - self.assertEqual( - check_if_network_environment_exists([self.instance]), {} - ) + self.assertEqual(check_if_network_environment_exists([self.instance]), {}) def test_instance_is_not_in_any_network_env_should_not_pass(self): self.assertEqual( check_if_network_environment_exists([self.instance]), - {self.instance: 'Network environment not found.'} + {self.instance: "Network environment not found."}, ) @@ -337,10 +318,7 @@ def _prepare_rack(self): @ddt class AutocompleteFunctionsTestCase(TestCase): @unpack - @data( - ([],), - ([DataCenterAssetFactory, DataCenterAssetFactory],) - ) + @data(([],), ([DataCenterAssetFactory, DataCenterAssetFactory],)) def test_autocomplete_service_env_should_return_false(self, factories): self.assertFalse( autocomplete_service_env([], [factory() for factory in factories]) @@ -348,101 +326,95 @@ def test_autocomplete_service_env_should_return_false(self, factories): def test_autocomplete_service_env_should_return_pk(self): asset = DataCenterAssetFactory(service_env=ServiceEnvironmentFactory()) - self.assertEqual( - asset.service_env.pk, autocomplete_service_env([], [asset]) - ) + self.assertEqual(asset.service_env.pk, autocomplete_service_env([], [asset])) class TestRender(TestCase): def test_hostname_is_rendered(self): deploy = _get_deployment() - result = _render_configuration('{{hostname}}', deploy) + result = _render_configuration("{{hostname}}", deploy) self.assertEqual(result, deploy.obj.hostname) def test_data_center_is_rendered(self): deploy = _get_deployment() - result = _render_configuration('{{dc}}', deploy) - self.assertEqual( - result, deploy.obj.rack.server_room.data_center.name - ) + result = _render_configuration("{{dc}}", deploy) + self.assertEqual(result, deploy.obj.rack.server_room.data_center.name) def test_configuration_path_is_rendered(self): deploy = _get_deployment() - result = _render_configuration('{{configuration_path}}', deploy) + result = _render_configuration("{{configuration_path}}", deploy) self.assertEqual(result, str(deploy.obj.configuration_path)) def test_configuration_class_is_rendered(self): deploy = _get_deployment() - result = _render_configuration( - '{{configuration_class_name}}', deploy - ) - self.assertEqual( - result, deploy.obj.configuration_path.class_name - ) + result = _render_configuration("{{configuration_class_name}}", deploy) + self.assertEqual(result, deploy.obj.configuration_path.class_name) def test_configuration_module_is_rendered(self): deploy = _get_deployment() - result = _render_configuration('{{configuration_module}}', deploy) - self.assertEqual( - result, deploy.obj.configuration_path.module.name - ) + result = _render_configuration("{{configuration_module}}", deploy) + self.assertEqual(result, deploy.obj.configuration_path.module.name) def test_service_env_is_rendered(self): deploy = _get_deployment() - result = _render_configuration('{{service_env}}', deploy) + result = _render_configuration("{{service_env}}", deploy) self.assertEqual(result, str(deploy.obj.service_env)) def test_service_uid_is_rendered(self): deploy = _get_deployment() - result = _render_configuration('{{service_uid}}', deploy) + result = _render_configuration("{{service_uid}}", deploy) self.assertEqual(result, deploy.obj.service_env.service.uid) def test_none_service_uid_renders_as_None(self): deploy = _get_deployment() deploy.obj.service_env = None - result = _render_configuration('{{service_uid}}', deploy) - self.assertEqual(result, 'None') + result = _render_configuration("{{service_uid}}", deploy) + self.assertEqual(result, "None") @ddt class TestRenderSlash(TestCase): - @override_settings(RALPH_INSTANCE='http://127.0.0.1:8000/') + @override_settings(RALPH_INSTANCE="http://127.0.0.1:8000/") @unpack @data( - ('{{done_url}}', 'http://127.0.0.1:8000/deployment/{}/mark_as_done'), - ('{{initrd}}', 'http://127.0.0.1:8000/deployment/{}/initrd'), - ('{{kernel}}', 'http://127.0.0.1:8000/deployment/{}/kernel'), - ('{{netboot}}', 'http://127.0.0.1:8000/deployment/{}/netboot'), - ('{{kickstart}}', 'http://127.0.0.1:8000/deployment/{}/kickstart'), - ('{{preseed}}', 'http://127.0.0.1:8000/deployment/{}/preseed'), - ('{{script}}', 'http://127.0.0.1:8000/deployment/{}/script'), - ('{{meta_data}}', 'http://127.0.0.1:8000/deployment/{}/meta-data'), - ('{{user_data}}', 'http://127.0.0.1:8000/deployment/{}/user-data'), - ('{{ralph_instance}}', 'http://127.0.0.1:8000/'), + ("{{done_url}}", "http://127.0.0.1:8000/deployment/{}/mark_as_done"), + ("{{initrd}}", "http://127.0.0.1:8000/deployment/{}/initrd"), + ("{{kernel}}", "http://127.0.0.1:8000/deployment/{}/kernel"), + ("{{netboot}}", "http://127.0.0.1:8000/deployment/{}/netboot"), + ("{{kickstart}}", "http://127.0.0.1:8000/deployment/{}/kickstart"), + ("{{preseed}}", "http://127.0.0.1:8000/deployment/{}/preseed"), + ("{{script}}", "http://127.0.0.1:8000/deployment/{}/script"), + ("{{meta_data}}", "http://127.0.0.1:8000/deployment/{}/meta-data"), + ("{{user_data}}", "http://127.0.0.1:8000/deployment/{}/user-data"), + ("{{ralph_instance}}", "http://127.0.0.1:8000/"), ) def test_single_slash_when_ralph_instance_has_one( - self, template_content, ok_url, + self, + template_content, + ok_url, ): deploy = _get_deployment() result = _render_configuration(template_content, deploy) self.assertEqual(result, ok_url.format(deploy.id)) - @override_settings(RALPH_INSTANCE='http://127.0.0.1:8000') + @override_settings(RALPH_INSTANCE="http://127.0.0.1:8000") @unpack @data( - ('{{done_url}}', 'http://127.0.0.1:8000/deployment/{}/mark_as_done'), - ('{{initrd}}', 'http://127.0.0.1:8000/deployment/{}/initrd'), - ('{{kernel}}', 'http://127.0.0.1:8000/deployment/{}/kernel'), - ('{{netboot}}', 'http://127.0.0.1:8000/deployment/{}/netboot'), - ('{{kickstart}}', 'http://127.0.0.1:8000/deployment/{}/kickstart'), - ('{{preseed}}', 'http://127.0.0.1:8000/deployment/{}/preseed'), - ('{{script}}', 'http://127.0.0.1:8000/deployment/{}/script'), - ('{{meta_data}}', 'http://127.0.0.1:8000/deployment/{}/meta-data'), - ('{{user_data}}', 'http://127.0.0.1:8000/deployment/{}/user-data'), - ('{{ralph_instance}}', 'http://127.0.0.1:8000'), + ("{{done_url}}", "http://127.0.0.1:8000/deployment/{}/mark_as_done"), + ("{{initrd}}", "http://127.0.0.1:8000/deployment/{}/initrd"), + ("{{kernel}}", "http://127.0.0.1:8000/deployment/{}/kernel"), + ("{{netboot}}", "http://127.0.0.1:8000/deployment/{}/netboot"), + ("{{kickstart}}", "http://127.0.0.1:8000/deployment/{}/kickstart"), + ("{{preseed}}", "http://127.0.0.1:8000/deployment/{}/preseed"), + ("{{script}}", "http://127.0.0.1:8000/deployment/{}/script"), + ("{{meta_data}}", "http://127.0.0.1:8000/deployment/{}/meta-data"), + ("{{user_data}}", "http://127.0.0.1:8000/deployment/{}/user-data"), + ("{{ralph_instance}}", "http://127.0.0.1:8000"), ) def test_single_slash_when_ralph_instance_has_no_slash( - self, template_content, ok_url, + self, + template_content, + ok_url, ): deploy = _get_deployment() result = _render_configuration(template_content, deploy) diff --git a/src/ralph/deployment/tests/test_forms.py b/src/ralph/deployment/tests/test_forms.py index a5a6c75cdc..c1fd611270 100644 --- a/src/ralph/deployment/tests/test_forms.py +++ b/src/ralph/deployment/tests/test_forms.py @@ -1,4 +1,3 @@ -import unittest from django.test import TestCase from ralph.deployment.forms import PrebootConfigurationForm @@ -7,9 +6,9 @@ class TestForm(TestCase): def test_invalid_configuration(self): form_data = { - 'configuration': '{% foo bar %} wrong template tag', - 'type': 1, - 'name': 'test' + "configuration": "{% foo bar %} wrong template tag", + "type": 1, + "name": "test", } form = PrebootConfigurationForm(data=form_data) self.assertFalse(form.is_valid()) diff --git a/src/ralph/deployment/tests/test_transitions.py b/src/ralph/deployment/tests/test_transitions.py index b79bc39c62..2a650fbb5b 100644 --- a/src/ralph/deployment/tests/test_transitions.py +++ b/src/ralph/deployment/tests/test_transitions.py @@ -7,16 +7,13 @@ from ralph.assets.models import AssetLastHostname from ralph.assets.tests.factories import EthernetFactory from ralph.data_center.models import DataCenterAsset -from ralph.data_center.tests.factories import ( - DataCenterAssetFactory, - RackFactory -) +from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory from ralph.lib.transitions.conf import TRANSITION_ORIGINAL_STATUS from ralph.lib.transitions.tests import TransitionTestCase from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory + NetworkFactory, ) from ralph.virtual.models import VirtualServer from ralph.virtual.tests.factories import VirtualServerFactory @@ -34,29 +31,29 @@ def setUpClass(cls): cls.hypervisor = DataCenterAssetFactory() cls.rack = RackFactory() cls.net_env = NetworkEnvironmentFactory( - hostname_template_prefix='server_1', - hostname_template_postfix='.mydc.net', + hostname_template_prefix="server_1", + hostname_template_postfix=".mydc.net", hostname_template_counter_length=5, ) cls.net_env_2 = NetworkEnvironmentFactory( - hostname_template_prefix='server_2', - hostname_template_postfix='.mydc2.net', + hostname_template_prefix="server_2", + hostname_template_postfix=".mydc2.net", hostname_template_counter_length=5, ) cls.net_env_3 = NetworkEnvironmentFactory( - hostname_template_prefix='server_3', - hostname_template_postfix='.mydc3.net', + hostname_template_prefix="server_3", + hostname_template_postfix=".mydc3.net", hostname_template_counter_length=5, ) cls.net = NetworkFactory( network_environment=cls.net_env, - address='10.20.30.0/24', + address="10.20.30.0/24", # reserve 10.20.30.1, 10.20.30.2, 10.20.30.3, 10.20.30.4, 10.20.30.5 - reserved_from_beginning=5 + reserved_from_beginning=5, ) cls.net_2 = NetworkFactory( network_environment=cls.net_env_2, - address='11.20.30.0/24', + address="11.20.30.0/24", ) cls.net.racks.add(cls.rack) cls.net_2.racks.add(cls.rack) @@ -65,13 +62,13 @@ def setUp(self): super().setUp() self.superuser = get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' + "test", "test@test.test", "test" ) self.api_client = APIClient() self.api_client.force_authenticate(self.superuser) self.gui_client = Client() - self.gui_client.login(username='test', password='test') + self.gui_client.login(username="test", password="test") AssetLastHostname.objects.create( prefix=self.net_env.hostname_template_prefix, @@ -83,81 +80,75 @@ def setUp(self): # Assign new hostname # ========================================================================= def _prepare_assign_new_hostname_transition(self): - actions = ['assign_new_hostname'] + actions = ["assign_new_hostname"] self.assign_new_hostname_transition = self._create_transition( - self.model, 'assign hostname', actions, 'status', - source=list(dict( - self.model._meta.get_field('status').choices - ).keys()), - target=str(TRANSITION_ORIGINAL_STATUS[0]) + self.model, + "assign hostname", + actions, + "status", + source=list(dict(self.model._meta.get_field("status").choices).keys()), + target=str(TRANSITION_ORIGINAL_STATUS[0]), )[1] def _prepare_assign_new_ip_transition(self): - actions = ['assign_new_ip'] + actions = ["assign_new_ip"] self.assign_assign_new_ip_transition = self._create_transition( - self.model, 'assign new ip', actions, 'status', - source=list(dict( - self.model._meta.get_field('status').choices - ).keys()), - target=str(TRANSITION_ORIGINAL_STATUS[0]) + self.model, + "assign new ip", + actions, + "status", + source=list(dict(self.model._meta.get_field("status").choices).keys()), + target=str(TRANSITION_ORIGINAL_STATUS[0]), )[1] def _prepare_assign_new_ip_with_dns_transition(self): - actions = ['assign_new_ip', 'assign_new_hostname'] + actions = ["assign_new_ip", "assign_new_hostname"] self.assign_assign_new_ip_with_dns_transition = self._create_transition( - self.model, 'assign new ip with dns', actions, 'status', - source=list(dict( - self.model._meta.get_field('status').choices - ).keys()), - target=str(TRANSITION_ORIGINAL_STATUS[0]) + self.model, + "assign new ip with dns", + actions, + "status", + source=list(dict(self.model._meta.get_field("status").choices).keys()), + target=str(TRANSITION_ORIGINAL_STATUS[0]), )[1] def _prepare_replace_ip_transition(self): - actions = ['replace_ip'] + actions = ["replace_ip"] self.assign_replace_ip_transition = self._create_transition( - self.model, 'replace ip', actions, 'status', - source=list(dict( - self.model._meta.get_field('status').choices - ).keys()), - target=str(TRANSITION_ORIGINAL_STATUS[0]) + self.model, + "replace ip", + actions, + "status", + source=list(dict(self.model._meta.get_field("status").choices).keys()), + target=str(TRANSITION_ORIGINAL_STATUS[0]), )[1] def _get_transition_view_url( - self, url_name, instance_id, transition_id=None, transition_name=None, - app_label=None, model=None + self, + url_name, + instance_id, + transition_id=None, + transition_name=None, + app_label=None, + model=None, ): if app_label and model: args = ( app_label, model, instance_id, - transition_name if transition_name else transition_id + transition_name if transition_name else transition_id, ) else: - args = ( - transition_id, - instance_id - ) + args = (transition_id, instance_id) return reverse(url_name, args=args) @unpack @data( - ( - lambda t: t._get_transition_view_url, 'transition-view', - False, False - ), - ( - lambda t: t._get_transition_view_url, 'transitions-view', - False, False - ), - ( - lambda t: t._get_transition_view_url, 'transitions-by-id-view', - True, True - ), - ( - lambda t: t._get_transition_view_url, 'transitions-by-name-view', - True, False - ), + (lambda t: t._get_transition_view_url, "transition-view", False, False), + (lambda t: t._get_transition_view_url, "transitions-view", False, False), + (lambda t: t._get_transition_view_url, "transitions-by-id-view", True, True), + (lambda t: t._get_transition_view_url, "transitions-by-name-view", True, False), ) def test_assign_new_hostname_through_api( self, data_func, url_name, new_transition, transition_by_id @@ -165,116 +156,92 @@ def test_assign_new_hostname_through_api( self._prepare_assign_new_hostname_transition() if new_transition: if transition_by_id: - kwargs = { - 'transition_id': self.assign_new_hostname_transition.id - } + kwargs = {"transition_id": self.assign_new_hostname_transition.id} else: - kwargs = { - 'transition_name': self.assign_new_hostname_transition.name - } + kwargs = {"transition_name": self.assign_new_hostname_transition.name} url = data_func(self)( url_name, self.instance.pk, app_label=self.instance._meta.app_label, model=self.instance._meta.model_name, - **kwargs + **kwargs, ) else: url = data_func(self)( - url_name, - self.instance.pk, - self.assign_new_hostname_transition.id + url_name, self.instance.pk, self.assign_new_hostname_transition.id ) - response = self.api_client.post( - url, - {'network_environment': self.net_env.pk} - ) + response = self.api_client.post(url, {"network_environment": self.net_env.pk}) self.assertEqual(response.status_code, 201) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_100011.mydc.net') + self.assertEqual(self.instance.hostname, "server_100011.mydc.net") # another request response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.assign_new_hostname_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.assign_new_hostname_transition.id, self.instance.pk), ), - {'network_environment': self.net_env.pk} + {"network_environment": self.net_env.pk}, ) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_100012.mydc.net') + self.assertEqual(self.instance.hostname, "server_100012.mydc.net") def test_assign_new_hostname_through_api_custom_hostname(self): self._prepare_assign_new_hostname_transition() response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.assign_new_hostname_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.assign_new_hostname_transition.id, self.instance.pk), ), { - 'network_environment': { - 'value': '__other__', - '__other__': 's12345.mydc.net', + "network_environment": { + "value": "__other__", + "__other__": "s12345.mydc.net", } }, - format='json', + format="json", ) self.assertEqual(response.status_code, 201) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 's12345.mydc.net') + self.assertEqual(self.instance.hostname, "s12345.mydc.net") def test_assign_new_hostname_through_api_without_asset_last_hostname(self): self._prepare_assign_new_hostname_transition() response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.assign_new_hostname_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.assign_new_hostname_transition.id, self.instance.pk), ), - {'network_environment': self.net_env_2.pk} + {"network_environment": self.net_env_2.pk}, ) self.assertEqual(response.status_code, 201) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_200001.mydc2.net') + self.assertEqual(self.instance.hostname, "server_200001.mydc2.net") # another request response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.assign_new_hostname_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.assign_new_hostname_transition.id, self.instance.pk), ), - {'network_environment': self.net_env_2.pk} + {"network_environment": self.net_env_2.pk}, ) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_200002.mydc2.net') + self.assertEqual(self.instance.hostname, "server_200002.mydc2.net") def test_assign_new_hostname_through_api_wrong_network_env(self): self._prepare_assign_new_hostname_transition() response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.assign_new_hostname_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.assign_new_hostname_transition.id, self.instance.pk), ), - {'network_environment': self.net_env_3.pk} + {"network_environment": self.net_env_3.pk}, ) self.assertEqual(response.status_code, 400) - self.assertIn('network_environment', response.data) + self.assertIn("network_environment", response.data) self.assertIn( '"{}" is not a valid choice.'.format(self.net_env_3.pk), - response.data['network_environment'] + response.data["network_environment"], ) def test_assign_new_hostname_through_gui(self): @@ -282,29 +249,29 @@ def test_assign_new_hostname_through_gui(self): response = self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.assign_new_hostname_transition.id) + args=(self.instance.id, self.assign_new_hostname_transition.id), ), - {'assign_new_hostname__network_environment': self.net_env.pk}, - follow=True + {"assign_new_hostname__network_environment": self.net_env.pk}, + follow=True, ) self.assertEqual(response.status_code, 200) self.assertTrue( response.redirect_chain[0][0], - reverse(self.redirect_url_name, args=(self.instance.id,)) + reverse(self.redirect_url_name, args=(self.instance.id,)), ) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_100011.mydc.net') + self.assertEqual(self.instance.hostname, "server_100011.mydc.net") # another assignment self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.assign_new_hostname_transition.id) + args=(self.instance.id, self.assign_new_hostname_transition.id), ), - {'assign_new_hostname__network_environment': self.net_env.pk}, - follow=True + {"assign_new_hostname__network_environment": self.net_env.pk}, + follow=True, ) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_100012.mydc.net') + self.assertEqual(self.instance.hostname, "server_100012.mydc.net") def test_assign_new_ip_through_gui(self): self._prepare_assign_new_ip_transition() @@ -313,27 +280,18 @@ def test_assign_new_ip_through_gui(self): response = self.gui_client.post( reverse( self.transition_url_name, - args=( - self.instance.id, - self.assign_assign_new_ip_transition.id - ) + args=(self.instance.id, self.assign_assign_new_ip_transition.id), ), - { - 'assign_new_ip__network': network.id - }, - follow=True + {"assign_new_ip__network": network.id}, + follow=True, ) self.assertEqual(response.status_code, 200) self.assertTrue( response.redirect_chain[0][0], - reverse(self.redirect_url_name, args=(self.instance.id,)) + reverse(self.redirect_url_name, args=(self.instance.id,)), ) self.instance.refresh_from_db() - self.assertTrue( - self.instance.ipaddresses.filter( - address=ip - ).exists() - ) + self.assertTrue(self.instance.ipaddresses.filter(address=ip).exists()) def test_assign_new_ip_with_dns_through_gui(self): self._prepare_assign_new_ip_with_dns_transition() @@ -344,195 +302,179 @@ def test_assign_new_ip_with_dns_through_gui(self): self.transition_url_name, args=( self.instance.id, - self.assign_assign_new_ip_with_dns_transition.id - ) + self.assign_assign_new_ip_with_dns_transition.id, + ), ), { - 'assign_new_hostname__network_environment': '__other__', - 'assign_new_hostname__network_environment__other__': 'hostname', # noqa - 'assign_new_ip__network': network.id, + "assign_new_hostname__network_environment": "__other__", + "assign_new_hostname__network_environment__other__": "hostname", # noqa + "assign_new_ip__network": network.id, }, - follow=True + follow=True, ) self.assertEqual(response.status_code, 200) self.assertTrue( response.redirect_chain[0][0], - reverse(self.redirect_url_name, args=(self.instance.id,)) + reverse(self.redirect_url_name, args=(self.instance.id,)), ) self.instance.refresh_from_db() - self.assertTrue( - self.instance.ipaddresses.filter( - address=ip - ).exists() - ) - self.assertEqual(self.instance.hostname, 'hostname') + self.assertTrue(self.instance.ipaddresses.filter(address=ip).exists()) + self.assertEqual(self.instance.hostname, "hostname") def test_replace_ip_through_gui(self): self._prepare_replace_ip_transition() ethernet = EthernetFactory(base_object=self.instance) ipaddress = IPAddressFactory( - address='10.20.30.1', - ethernet=ethernet, - hostname='test_hostname' + address="10.20.30.1", ethernet=ethernet, hostname="test_hostname" ) network = self.instance._get_available_networks()[0] response = self.gui_client.post( reverse( self.transition_url_name, - args=( - self.instance.id, - self.assign_replace_ip_transition.id - ) + args=(self.instance.id, self.assign_replace_ip_transition.id), ), - { - 'replace_ip__ipaddress': ipaddress.id, - 'replace_ip__network': network.id - }, - follow=True + {"replace_ip__ipaddress": ipaddress.id, "replace_ip__network": network.id}, + follow=True, ) self.assertEqual(response.status_code, 200) self.assertTrue( response.redirect_chain[0][0], - reverse(self.redirect_url_name, args=(self.instance.id,)) + reverse(self.redirect_url_name, args=(self.instance.id,)), ) ipaddress.refresh_from_db() - self.assertNotEqual(ipaddress.address, '10.20.30.1') + self.assertNotEqual(ipaddress.address, "10.20.30.1") def test_assign_new_hostname_through_gui_with_other_value(self): self._prepare_assign_new_hostname_transition() response = self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.assign_new_hostname_transition.id) + args=(self.instance.id, self.assign_new_hostname_transition.id), ), { - 'assign_new_hostname__network_environment': '__other__', - 'assign_new_hostname__network_environment__other__': 's1234.mydc.net' # noqa + "assign_new_hostname__network_environment": "__other__", + "assign_new_hostname__network_environment__other__": "s1234.mydc.net", # noqa }, - follow=True + follow=True, ) self.assertEqual(response.status_code, 200) self.assertTrue( response.redirect_chain[0][0], - reverse(self.redirect_url_name, args=(self.instance.id,)) + reverse(self.redirect_url_name, args=(self.instance.id,)), ) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 's1234.mydc.net') + self.assertEqual(self.instance.hostname, "s1234.mydc.net") def test_assign_new_hostname_through_gui_without_asset_last_hostname(self): self._prepare_assign_new_hostname_transition() response = self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.assign_new_hostname_transition.id) + args=(self.instance.id, self.assign_new_hostname_transition.id), ), - {'assign_new_hostname__network_environment': self.net_env_2.pk}, - follow=True + {"assign_new_hostname__network_environment": self.net_env_2.pk}, + follow=True, ) self.assertEqual(response.status_code, 200) self.assertTrue( response.redirect_chain[0][0], - reverse(self.redirect_url_name, args=(self.instance.id,)) + reverse(self.redirect_url_name, args=(self.instance.id,)), ) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_200001.mydc2.net') + self.assertEqual(self.instance.hostname, "server_200001.mydc2.net") # another assignment self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.assign_new_hostname_transition.id) + args=(self.instance.id, self.assign_new_hostname_transition.id), ), - {'assign_new_hostname__network_environment': self.net_env_2.pk}, - follow=True + {"assign_new_hostname__network_environment": self.net_env_2.pk}, + follow=True, ) self.instance.refresh_from_db() - self.assertEqual(self.instance.hostname, 'server_200002.mydc2.net') + self.assertEqual(self.instance.hostname, "server_200002.mydc2.net") def test_assign_new_hostname_through_gui_with_wrong_network_env(self): self._prepare_assign_new_hostname_transition() response = self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.assign_new_hostname_transition.id) + args=(self.instance.id, self.assign_new_hostname_transition.id), ), - {'assign_new_hostname__network_environment': self.net_env_3.pk}, + {"assign_new_hostname__network_environment": self.net_env_3.pk}, # no following redirects here! ) self.assertEqual(response.status_code, 200) self.assertIn( - 'assign_new_hostname__network_environment', - response.context_data['form'].errors + "assign_new_hostname__network_environment", + response.context_data["form"].errors, ) # ========================================================================= # Create DHCP entries # ========================================================================= def _prepare_create_dhcp_entries_transition(self): - actions = ['create_dhcp_entries', 'clean_ipaddresses', 'clean_dhcp'] + actions = ["create_dhcp_entries", "clean_ipaddresses", "clean_dhcp"] self.create_dhcp_entries_transition = self._create_transition( - self.model, 'create dhcp entries', actions, 'status', - source=list(dict( - self.model._meta.get_field('status').choices - ).keys()), - target=str(TRANSITION_ORIGINAL_STATUS[0]) + self.model, + "create dhcp entries", + actions, + "status", + source=list(dict(self.model._meta.get_field("status").choices).keys()), + target=str(TRANSITION_ORIGINAL_STATUS[0]), )[1] def _get_create_dhcp_entries_primitive_data(self): return { - 'ip_or_network': self.net.pk, - 'ethernet': self.eth.id, + "ip_or_network": self.net.pk, + "ethernet": self.eth.id, } def _get_create_dhcp_entries_compound_data(self): return { - 'ip_or_network': { - 'value': self.net.pk, + "ip_or_network": { + "value": self.net.pk, }, - 'ethernet': self.eth.id, + "ethernet": self.eth.id, } def _get_create_dhcp_entries_compound_data_other(self): return { - 'ip_or_network': { - 'value': '__other__', - '__other__': '10.20.30.22', + "ip_or_network": { + "value": "__other__", + "__other__": "10.20.30.22", }, - 'ethernet': self.eth.id, + "ethernet": self.eth.id, } def _get_create_dhcp_entries_gui(self): return { - 'create_dhcp_entries__ip_or_network': self.net.pk, - 'create_dhcp_entries__ethernet': self.eth.id, + "create_dhcp_entries__ip_or_network": self.net.pk, + "create_dhcp_entries__ethernet": self.eth.id, } def _get_create_dhcp_entries_gui_with_other(self): return { - 'create_dhcp_entries__ip_or_network': '__other__', - 'create_dhcp_entries__ip_or_network__other__': '10.20.30.22', - 'create_dhcp_entries__ethernet': self.eth.id, + "create_dhcp_entries__ip_or_network": "__other__", + "create_dhcp_entries__ip_or_network__other__": "10.20.30.22", + "create_dhcp_entries__ethernet": self.eth.id, } @unpack @data( - (lambda t: t._get_create_dhcp_entries_primitive_data(), '10.20.30.6'), - (lambda t: t._get_create_dhcp_entries_compound_data(), '10.20.30.6'), - (lambda t: t._get_create_dhcp_entries_compound_data_other(), '10.20.30.22'), + (lambda t: t._get_create_dhcp_entries_primitive_data(), "10.20.30.6"), + (lambda t: t._get_create_dhcp_entries_compound_data(), "10.20.30.6"), + (lambda t: t._get_create_dhcp_entries_compound_data_other(), "10.20.30.22"), ) - def test_create_dhcp_entries_through_api( - self, data_func, assigned_ip - ): + def test_create_dhcp_entries_through_api(self, data_func, assigned_ip): self._prepare_create_dhcp_entries_transition() response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.create_dhcp_entries_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.create_dhcp_entries_transition.id, self.instance.pk), ), data_func(self), - format='json', + format="json", ) self.assertEqual(response.status_code, 201) self.instance.refresh_from_db() @@ -545,66 +487,56 @@ def test_create_dhcp_entries_through_api_with_wrong_ethernet(self): eth = EthernetFactory().pk response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.create_dhcp_entries_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.create_dhcp_entries_transition.id, self.instance.pk), ), { - 'ip_or_network': self.net.pk, - 'ethernet': eth, + "ip_or_network": self.net.pk, + "ethernet": eth, }, - format='json', + format="json", ) self.assertEqual(response.status_code, 400) self.assertIn( - '"{}" is not a valid choice.'.format(eth), - response.data['ethernet'] + '"{}" is not a valid choice.'.format(eth), response.data["ethernet"] ) def test_create_dhcp_entries_through_api_with_occupied_ip(self): self._prepare_create_dhcp_entries_transition() IPAddressFactory( - address='10.20.30.40', - ethernet__base_object=DataCenterAssetFactory() + address="10.20.30.40", ethernet__base_object=DataCenterAssetFactory() ) response = self.api_client.post( reverse( - 'transitions-view', - args=( - self.create_dhcp_entries_transition.id, - self.instance.pk - ) + "transitions-view", + args=(self.create_dhcp_entries_transition.id, self.instance.pk), ), { - 'ip_or_network': { - 'value': '__other__', - '__other__': '10.20.30.40', + "ip_or_network": { + "value": "__other__", + "__other__": "10.20.30.40", }, - 'ethernet': self.eth.id, + "ethernet": self.eth.id, }, - format='json', + format="json", ) self.assertEqual(response.status_code, 400) self.assertIn( - 'IP 10.20.30.40 is already assigned to other object!', - response.data['ip_or_network'] + "IP 10.20.30.40 is already assigned to other object!", + response.data["ip_or_network"], ) @unpack @data( - (lambda t: t._get_create_dhcp_entries_gui(), '10.20.30.6'), - (lambda t: t._get_create_dhcp_entries_gui_with_other(), '10.20.30.22'), + (lambda t: t._get_create_dhcp_entries_gui(), "10.20.30.6"), + (lambda t: t._get_create_dhcp_entries_gui_with_other(), "10.20.30.22"), ) - def test_create_dhcp_entries_through_gui( - self, data_func, assigned_ip - ): + def test_create_dhcp_entries_through_gui(self, data_func, assigned_ip): self._prepare_create_dhcp_entries_transition() response = self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.create_dhcp_entries_transition.id) + args=(self.instance.id, self.create_dhcp_entries_transition.id), ), data_func(self), follow=True, @@ -612,7 +544,7 @@ def test_create_dhcp_entries_through_gui( self.assertEqual(response.status_code, 200) self.assertTrue( response.redirect_chain[0][0], - reverse(self.redirect_url_name, args=(self.instance.id,)) + reverse(self.redirect_url_name, args=(self.instance.id,)), ) self.instance.refresh_from_db() self.eth.refresh_from_db() @@ -625,40 +557,38 @@ def test_create_dhcp_entries_through_gui_with_wrong_ethernet(self): response = self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.create_dhcp_entries_transition.id) + args=(self.instance.id, self.create_dhcp_entries_transition.id), ), { - 'create_dhcp_entries__ip_or_network': self.net.pk, - 'create_dhcp_entries__ethernet': eth, + "create_dhcp_entries__ip_or_network": self.net.pk, + "create_dhcp_entries__ethernet": eth, }, ) self.assertEqual(response.status_code, 200) self.assertIn( - 'create_dhcp_entries__ethernet', - response.context_data['form'].errors + "create_dhcp_entries__ethernet", response.context_data["form"].errors ) def test_create_dhcp_entries_through_gui_with_occupied_ip(self): self._prepare_create_dhcp_entries_transition() IPAddressFactory( - address='10.20.30.40', - ethernet__base_object=DataCenterAssetFactory() + address="10.20.30.40", ethernet__base_object=DataCenterAssetFactory() ) response = self.gui_client.post( reverse( self.transition_url_name, - args=(self.instance.id, self.create_dhcp_entries_transition.id) + args=(self.instance.id, self.create_dhcp_entries_transition.id), ), { - 'create_dhcp_entries__ip_or_network': '__other__', - 'create_dhcp_entries__ip_or_network__other__': '10.20.30.40', - 'create_dhcp_entries__ethernet': self.eth.id, + "create_dhcp_entries__ip_or_network": "__other__", + "create_dhcp_entries__ip_or_network__other__": "10.20.30.40", + "create_dhcp_entries__ethernet": self.eth.id, }, ) self.assertEqual(response.status_code, 200) self.assertEqual( - response.context_data['form'].errors['create_dhcp_entries__ip_or_network'], # noqa - ['IP 10.20.30.40 is already assigned to other object!'] + response.context_data["form"].errors["create_dhcp_entries__ip_or_network"], # noqa + ["IP 10.20.30.40 is already assigned to other object!"], ) @@ -667,8 +597,8 @@ class VirtualServerDeploymentTransitionTestCase( ): model = VirtualServer factory = VirtualServerFactory - transition_url_name = 'admin:virtual_virtualserver_transition' - redirect_url_name = 'admin:virtual_virtualserver_change' + transition_url_name = "admin:virtual_virtualserver_transition" + redirect_url_name = "admin:virtual_virtualserver_change" @classmethod def setUpClass(cls): @@ -680,9 +610,7 @@ def setUpClass(cls): def setUp(self): super().setUp() self.instance = VirtualServerFactory(parent=self.parent) - self.eth = EthernetFactory( - base_object=self.instance, mac='10:20:30:40:50:60' - ) + self.eth = EthernetFactory(base_object=self.instance, mac="10:20:30:40:50:60") class DataCenterAssetDeploymentTransitionTestCase( @@ -690,12 +618,10 @@ class DataCenterAssetDeploymentTransitionTestCase( ): model = DataCenterAsset factory = DataCenterAssetFactory - transition_url_name = 'admin:data_center_datacenterasset_transition' - redirect_url_name = 'admin:data_center_datacenterasset_change' + transition_url_name = "admin:data_center_datacenterasset_transition" + redirect_url_name = "admin:data_center_datacenterasset_change" def setUp(self): super().setUp() self.instance = DataCenterAssetFactory(rack=self.rack) - self.eth = EthernetFactory( - base_object=self.instance, mac='10:20:30:40:50:60' - ) + self.eth = EthernetFactory(base_object=self.instance, mac="10:20:30:40:50:60") diff --git a/src/ralph/deployment/urls.py b/src/ralph/deployment/urls.py index e33f9cf65f..7aa42cb724 100644 --- a/src/ralph/deployment/urls.py +++ b/src/ralph/deployment/urls.py @@ -1,50 +1,28 @@ from django.conf.urls import url -from ralph.deployment.views import ( - config, - deployment_base, - done_ping, - files, - ipxe -) +from ralph.deployment.views import config, deployment_base, done_ping, files, ipxe urlpatterns = [ + url(r"^boot.ipxe$", ipxe, name="deployment_ipxe"), + url(r"^(?P[-\w]+)/boot.ipxe$", ipxe, name="deployment_ipxe"), url( - r'^boot.ipxe$', - ipxe, - name='deployment_ipxe' - ), - url( - r'^(?P[-\w]+)/boot.ipxe$', - ipxe, - name='deployment_ipxe' - ), - url( - r'^(?P[-\w]+)/' - r'(' - r'?P' - r'kickstart|' - r'preseed|' - r'meta-data|' - r'user-data|' - r'script' - r')$', + r"^(?P[-\w]+)/" + r"(" + r"?P" + r"kickstart|" + r"preseed|" + r"meta-data|" + r"user-data|" + r"script" + r")$", config, - name='deployment_config' + name="deployment_config", ), url( - r'^(?P[-\w]+)/(?Pkernel|initrd|netboot)$', + r"^(?P[-\w]+)/(?Pkernel|initrd|netboot)$", files, - name='deployment_files' - ), - url( - r'^(?P[-\w]+)/mark_as_done$', - done_ping, - name='deployment_done' - ), - url( - r'^(?P[-\w]+)/$', - deployment_base, - name='deployment_base' + name="deployment_files", ), + url(r"^(?P[-\w]+)/mark_as_done$", done_ping, name="deployment_done"), + url(r"^(?P[-\w]+)/$", deployment_base, name="deployment_base"), ] diff --git a/src/ralph/deployment/utils.py b/src/ralph/deployment/utils.py index 00886b513c..b5682b5d08 100644 --- a/src/ralph/deployment/utils.py +++ b/src/ralph/deployment/utils.py @@ -8,124 +8,122 @@ def _render_configuration(configuration, deployment, disable_reverse=False): def url(name, kwargs): if disable_reverse: - return '{}({})'.format( - name, ', '.join([str(value) for value in kwargs.values()]) + return "{}({})".format( + name, ", ".join([str(value) for value in kwargs.values()]) ) return reverse(name, kwargs=kwargs) template = Template(configuration) ralph_instance = settings.RALPH_INSTANCE - ethernet = deployment.params.get('create_dhcp_entries__ethernet') - context = Context({ - 'configuration_path': str(deployment.obj.configuration_path), - 'configuration_class_name': ( - deployment.obj.configuration_path.class_name if - deployment.obj.configuration_path else None - ), - 'configuration_module': ( - deployment.obj.configuration_path.module.name if - deployment.obj.configuration_path else None - ), - 'ralph_instance': ralph_instance, - 'deployment_id': deployment.id, - 'deployment_base': urljoin( - ralph_instance, - url( - 'deployment_base', - kwargs={ - 'deployment_id': deployment.id - } - ) - ), - 'kickstart': urljoin( - ralph_instance, - url( - 'deployment_config', - kwargs={ - 'deployment_id': deployment.id, - 'config_type': 'kickstart', - } + ethernet = deployment.params.get("create_dhcp_entries__ethernet") + context = Context( + { + "configuration_path": str(deployment.obj.configuration_path), + "configuration_class_name": ( + deployment.obj.configuration_path.class_name + if deployment.obj.configuration_path + else None ), - ), - 'preseed': urljoin( - ralph_instance, - url( - 'deployment_config', - kwargs={ - 'deployment_id': deployment.id, - 'config_type': 'preseed', - } + "configuration_module": ( + deployment.obj.configuration_path.module.name + if deployment.obj.configuration_path + else None ), - ), - 'script': urljoin( - ralph_instance, - url( - 'deployment_config', - kwargs={ - 'deployment_id': deployment.id, - 'config_type': 'script', - } + "ralph_instance": ralph_instance, + "deployment_id": deployment.id, + "deployment_base": urljoin( + ralph_instance, + url("deployment_base", kwargs={"deployment_id": deployment.id}), ), - ), - 'meta_data': urljoin( - ralph_instance, - url( - 'deployment_config', - kwargs={ - 'deployment_id': deployment.id, - 'config_type': 'meta-data', - } + "kickstart": urljoin( + ralph_instance, + url( + "deployment_config", + kwargs={ + "deployment_id": deployment.id, + "config_type": "kickstart", + }, + ), ), - ), - 'user_data': urljoin( - ralph_instance, - url( - 'deployment_config', - kwargs={ - 'deployment_id': deployment.id, - 'config_type': 'user-data', - } + "preseed": urljoin( + ralph_instance, + url( + "deployment_config", + kwargs={ + "deployment_id": deployment.id, + "config_type": "preseed", + }, + ), ), - ), - 'initrd': urljoin( - ralph_instance, - url( - 'deployment_files', - kwargs={'deployment_id': deployment.id, 'file_type': 'initrd'} - ) - ), - 'kernel': urljoin( - ralph_instance, - url( - 'deployment_files', - kwargs={'deployment_id': deployment.id, 'file_type': 'kernel'} + "script": urljoin( + ralph_instance, + url( + "deployment_config", + kwargs={ + "deployment_id": deployment.id, + "config_type": "script", + }, + ), ), - ), - 'netboot': urljoin( - ralph_instance, - url( - 'deployment_files', - kwargs={'deployment_id': deployment.id, 'file_type': 'netboot'} + "meta_data": urljoin( + ralph_instance, + url( + "deployment_config", + kwargs={ + "deployment_id": deployment.id, + "config_type": "meta-data", + }, + ), ), - ), - 'dc': deployment.obj.rack.server_room.data_center.name, - 'domain': ( - deployment.obj.network_environment.domain - if deployment.obj.network_environment else None - ), - 'hostname': deployment.obj.hostname, - 'service_env': str(deployment.obj.service_env), - 'service_uid': ( - deployment.obj.service_env.service.uid if - deployment.obj.service_env else None - ), - 'done_url': urljoin( - ralph_instance, - url( - 'deployment_done', - kwargs={'deployment_id': deployment.id} - ) - ), - 'mac': ethernet.mac if ethernet else None, - }) + "user_data": urljoin( + ralph_instance, + url( + "deployment_config", + kwargs={ + "deployment_id": deployment.id, + "config_type": "user-data", + }, + ), + ), + "initrd": urljoin( + ralph_instance, + url( + "deployment_files", + kwargs={"deployment_id": deployment.id, "file_type": "initrd"}, + ), + ), + "kernel": urljoin( + ralph_instance, + url( + "deployment_files", + kwargs={"deployment_id": deployment.id, "file_type": "kernel"}, + ), + ), + "netboot": urljoin( + ralph_instance, + url( + "deployment_files", + kwargs={"deployment_id": deployment.id, "file_type": "netboot"}, + ), + ), + "dc": deployment.obj.rack.server_room.data_center.name, + "domain": ( + deployment.obj.network_environment.domain + if deployment.obj.network_environment + else None + ), + "hostname": deployment.obj.hostname, + "service_env": str(deployment.obj.service_env), + "service_uid": ( + deployment.obj.service_env.service.uid + if deployment.obj.service_env + else None + ), + "done_url": urljoin( + ralph_instance, + url("deployment_done", kwargs={"deployment_id": deployment.id}), + ), + "mac": ethernet.mac if ethernet else None, + } + ) return template.render(context) diff --git a/src/ralph/deployment/views.py b/src/ralph/deployment/views.py index e7dd251ef0..54a3f96ea2 100644 --- a/src/ralph/deployment/views.py +++ b/src/ralph/deployment/views.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) -DEPLOYMENT_404_MSG = 'Deployment %s doesn\'t exist' +DEPLOYMENT_404_MSG = "Deployment %s doesn't exist" def get_object_or_404_with_message(model, msg, logger_args, **kwargs): @@ -22,18 +22,18 @@ def get_object_or_404_with_message(model, msg, logger_args, **kwargs): def _get_preboot(deployment_id): - error_msg = 'Deployment with UUID: %s doesn\'t exist' + error_msg = "Deployment with UUID: %s doesn't exist" try: preboot_id = get_object_or_404_with_message( model=Deployment, msg=error_msg, logger_args=[deployment_id], - id=deployment_id + id=deployment_id, ).preboot return Preboot.objects.get(id=preboot_id) except ValueError: - logger.warning('Incorrect UUID: %s', deployment_id) - raise SuspiciousOperation('Malformed UUID') + logger.warning("Incorrect UUID: %s", deployment_id) + raise SuspiciousOperation("Malformed UUID") def ipxe(request, deployment_id=None): @@ -55,20 +55,18 @@ def ipxe(request, deployment_id=None): else: deployment = Deployment.get_deployment_for_ip(ip) except Ethernet.DoesNotExist: - logger.warning('Deployment does not exists for ip: %s', ip) + logger.warning("Deployment does not exists for ip: %s", ip) raise Http404 except Deployment.DoesNotExist: logger.warning(DEPLOYMENT_404_MSG, deployment_id) raise Http404 preboot = _get_preboot(deployment.id) - configuration = _render_configuration( - preboot.get_configuration('ipxe'), deployment - ) - return HttpResponse(configuration, content_type='text/plain') + configuration = _render_configuration(preboot.get_configuration("ipxe"), deployment) + return HttpResponse(configuration, content_type="text/plain") def deployment_base(*_args, **_kwargs): - return HttpResponse(content_type='text/plain') + return HttpResponse(content_type="text/plain") def config(request, deployment_id, config_type): @@ -88,21 +86,18 @@ def config(request, deployment_id, config_type): preboot = _get_preboot(deployment_id) configuration = preboot.get_configuration(config_type.replace("-", "_")) if configuration is None: - logger.warning( - '%s for deployment %s doesn\'t exist', - config_type, deployment_id - ) + logger.warning("%s for deployment %s doesn't exist", config_type, deployment_id) raise Http404 deployment = get_object_or_404_with_message( model=Deployment, msg=DEPLOYMENT_404_MSG, logger_args=[deployment_id], - id=deployment_id + id=deployment_id, ) configuration = _render_configuration(configuration, deployment) return HttpResponse( - configuration.replace('\r\n', '\n').replace('\r', '\n'), - content_type='text/plain' + configuration.replace("\r\n", "\n").replace("\r", "\n"), + content_type="text/plain", ) @@ -124,8 +119,7 @@ def files(request, file_type, deployment_id): file_url = preboot.get_file_url(file_type) if file_url is None: logger.warning( - 'File %s for deployment %s doesn\'t exist', - file_type, deployment_id + "File %s for deployment %s doesn't exist", file_type, deployment_id ) raise Http404 return HttpResponseRedirect(file_url) @@ -144,9 +138,5 @@ def done_ping(request, deployment_id): preboot.increment_used_counter() ip = get_client_ip(request) Deployment.mark_as_done(deployment_id) - logger.info( - 'Deployment {} for {} marked as done.'.format( - deployment_id, ip - ) - ) - return HttpResponse('marked', content_type='text/plain') + logger.info("Deployment {} for {} marked as done.".format(deployment_id, ip)) + return HttpResponse("marked", content_type="text/plain") diff --git a/src/ralph/dhcp/admin.py b/src/ralph/dhcp/admin.py index c62b82e52f..0a4b4b916c 100644 --- a/src/ralph/dhcp/admin.py +++ b/src/ralph/dhcp/admin.py @@ -5,27 +5,24 @@ from ralph.admin.decorators import register from ralph.admin.mixins import RalphAdmin, RalphTabularInline -from ralph.dhcp.models import ( - DHCPServer, - DNSServer, - DNSServerGroup, - DNSServerGroupOrder -) +from ralph.dhcp.models import DHCPServer, DNSServer, DNSServerGroup, DNSServerGroupOrder from ralph.lib.table.table import TableWithUrl @register(DHCPServer) class DHCPServerAdmin(RalphAdmin): - list_display = ['ip', 'last_synchronized_formatted', 'network_environment'] - list_select_related = ['network_environment'] - search_fields = ['ip'] + list_display = ["ip", "last_synchronized_formatted", "network_environment"] + list_select_related = ["network_environment"] + search_fields = ["ip"] def last_synchronized_formatted(self, obj): - return _('{} ({} ago)'.format( - date(obj.last_synchronized), - timesince_filter(obj.last_synchronized) - )) - last_synchronized_formatted.short_description = 'Last synchronized' + return _( + "{} ({} ago)".format( + date(obj.last_synchronized), timesince_filter(obj.last_synchronized) + ) + ) + + last_synchronized_formatted.short_description = "Last synchronized" @register(DNSServer) @@ -41,32 +38,40 @@ class DNSServerGroupOrderInline(RalphTabularInline): @register(DNSServerGroup) class DNSServerGroupAdmin(RalphAdmin): inlines = (DNSServerGroupOrderInline,) - list_display = ('name', 'servers_formatted') - readonly_fields = ['networks'] + list_display = ("name", "servers_formatted") + readonly_fields = ["networks"] fieldsets = ( - (_(''), { - 'fields': ( - 'name', - 'networks', - ) - }), + ( + _(""), + { + "fields": ( + "name", + "networks", + ) + }, + ), ) def get_queryset(self, request): - return super().get_queryset(request).prefetch_related( - Prefetch( - 'server_group_order__dns_server', - queryset=DNSServer.objects.all().only('ip_address').order_by( - 'server_group_order__order' + return ( + super() + .get_queryset(request) + .prefetch_related( + Prefetch( + "server_group_order__dns_server", + queryset=DNSServer.objects.all() + .only("ip_address") + .order_by("server_group_order__order"), ) ) ) def servers_formatted(self, obj): - return ', '.join([ - d.dns_server.ip_address for d in obj.server_group_order.all() - ]) - servers_formatted.short_description = 'DNS Servers' + return ", ".join( + [d.dns_server.ip_address for d in obj.server_group_order.all()] + ) + + servers_formatted.short_description = "DNS Servers" @mark_safe def networks(self, obj): @@ -74,10 +79,11 @@ def networks(self, obj): if networks: result = TableWithUrl( networks, - ['name', 'address', 'network_environment'], - url_field='name', + ["name", "address", "network_environment"], + url_field="name", ).render() else: - result = '–' + result = "–" return result - networks.short_description = _('in networks') + + networks.short_description = _("in networks") diff --git a/src/ralph/dhcp/api.py b/src/ralph/dhcp/api.py index cc3e79aab4..039ac80e84 100644 --- a/src/ralph/dhcp/api.py +++ b/src/ralph/dhcp/api.py @@ -26,6 +26,6 @@ class DNSServerGroupViewSet(RalphAPIViewSet): serializer_class = DNSServerGroupSerializer -router.register(r'dns-servers', DNSServerViewSet) -router.register(r'dns-server-group', DNSServerGroupViewSet) +router.register(r"dns-servers", DNSServerViewSet) +router.register(r"dns-server-group", DNSServerGroupViewSet) urlpatterns = [] diff --git a/src/ralph/dhcp/migrations/0001_initial.py b/src/ralph/dhcp/migrations/0001_initial.py index 8890b4836a..5c0823b261 100644 --- a/src/ralph/dhcp/migrations/0001_initial.py +++ b/src/ralph/dhcp/migrations/0001_initial.py @@ -5,33 +5,62 @@ class Migration(migrations.Migration): - - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='DHCPServer', + name="DHCPServer", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('ip', models.GenericIPAddressField(verbose_name='IP address', unique=True)), - ('last_synchronized', models.DateTimeField(blank=True, null=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "ip", + models.GenericIPAddressField( + verbose_name="IP address", unique=True + ), + ), + ("last_synchronized", models.DateTimeField(blank=True, null=True)), ], options={ - 'verbose_name': 'DHCP Server', - 'verbose_name_plural': 'DHCP Servers', + "verbose_name": "DHCP Server", + "verbose_name_plural": "DHCP Servers", }, ), migrations.CreateModel( - name='DNSServer', + name="DNSServer", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('ip_address', models.GenericIPAddressField(verbose_name='IP address', unique=True)), - ('is_default', models.BooleanField(verbose_name='is default', db_index=True, default=False)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "ip_address", + models.GenericIPAddressField( + verbose_name="IP address", unique=True + ), + ), + ( + "is_default", + models.BooleanField( + verbose_name="is default", db_index=True, default=False + ), + ), ], options={ - 'verbose_name': 'DNS Server', - 'verbose_name_plural': 'DNS Servers', + "verbose_name": "DNS Server", + "verbose_name_plural": "DNS Servers", }, ), ] diff --git a/src/ralph/dhcp/migrations/0002_dhcpentry.py b/src/ralph/dhcp/migrations/0002_dhcpentry.py index c3b67619ce..17514d5e85 100644 --- a/src/ralph/dhcp/migrations/0002_dhcpentry.py +++ b/src/ralph/dhcp/migrations/0002_dhcpentry.py @@ -1,24 +1,22 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('networks', '0001_initial'), - ('dhcp', '0001_initial'), + ("networks", "0001_initial"), + ("dhcp", "0001_initial"), ] operations = [ migrations.CreateModel( - name='DHCPEntry', - fields=[ - ], + name="DHCPEntry", + fields=[], options={ - 'proxy': True, + "proxy": True, }, - bases=('networks.ipaddress',), + bases=("networks.ipaddress",), ), ] diff --git a/src/ralph/dhcp/migrations/0003_dhcpserver_network_environment.py b/src/ralph/dhcp/migrations/0003_dhcpserver_network_environment.py index 6b259f05f9..4163162264 100644 --- a/src/ralph/dhcp/migrations/0003_dhcpserver_network_environment.py +++ b/src/ralph/dhcp/migrations/0003_dhcpserver_network_environment.py @@ -6,17 +6,22 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0007_auto_20160804_1409'), - ('dhcp', '0002_dhcpentry'), + ("networks", "0007_auto_20160804_1409"), + ("dhcp", "0002_dhcpentry"), ] operations = [ migrations.AddField( - model_name='dhcpserver', - name='network_environment', - field=models.ForeignKey(to='networks.NetworkEnvironment', null=True, blank=True, default=None, on_delete=django.db.models.deletion.CASCADE), + model_name="dhcpserver", + name="network_environment", + field=models.ForeignKey( + to="networks.NetworkEnvironment", + null=True, + blank=True, + default=None, + on_delete=django.db.models.deletion.CASCADE, + ), preserve_default=False, ), ] diff --git a/src/ralph/dhcp/migrations/0004_add_dns_server_group.py b/src/ralph/dhcp/migrations/0004_add_dns_server_group.py index 724b82a3f6..18c380f035 100644 --- a/src/ralph/dhcp/migrations/0004_add_dns_server_group.py +++ b/src/ralph/dhcp/migrations/0004_add_dns_server_group.py @@ -7,43 +7,74 @@ class Migration(migrations.Migration): - dependencies = [ - ('dhcp', '0003_dhcpserver_network_environment'), + ("dhcp", "0003_dhcpserver_network_environment"), ] operations = [ migrations.CreateModel( - name='DNSServerGroup', + name="DNSServerGroup", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), ], options={ - 'verbose_name': 'DNS Server Group', - 'verbose_name_plural': 'DNS Server Groups', + "verbose_name": "DNS Server Group", + "verbose_name_plural": "DNS Server Groups", }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='DNSServerGroupOrder', + name="DNSServerGroupOrder", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(db_index=True)), - ('dns_server', models.ForeignKey(to='dhcp.DNSServer', on_delete=django.db.models.deletion.CASCADE)), - ('dns_server_group', models.ForeignKey(to='dhcp.DNSServerGroup', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(db_index=True)), + ( + "dns_server", + models.ForeignKey( + to="dhcp.DNSServer", on_delete=django.db.models.deletion.CASCADE + ), + ), + ( + "dns_server_group", + models.ForeignKey( + to="dhcp.DNSServerGroup", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'ordering': ('order',), + "ordering": ("order",), }, ), migrations.AddField( - model_name='dnsservergroup', - name='servers', - field=models.ManyToManyField(through='dhcp.DNSServerGroupOrder', to='dhcp.DNSServer'), + model_name="dnsservergroup", + name="servers", + field=models.ManyToManyField( + through="dhcp.DNSServerGroupOrder", to="dhcp.DNSServer" + ), ), migrations.AlterUniqueTogether( - name='dnsservergrouporder', - unique_together=set([('dns_server_group', 'dns_server')]), + name="dnsservergrouporder", + unique_together=set([("dns_server_group", "dns_server")]), ), ] diff --git a/src/ralph/dhcp/migrations/0005_change_related_name.py b/src/ralph/dhcp/migrations/0005_change_related_name.py index 8f1be6b8e9..1b37a7f41d 100644 --- a/src/ralph/dhcp/migrations/0005_change_related_name.py +++ b/src/ralph/dhcp/migrations/0005_change_related_name.py @@ -6,20 +6,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('dhcp', '0004_add_dns_server_group'), + ("dhcp", "0004_add_dns_server_group"), ] operations = [ migrations.AlterField( - model_name='dnsservergrouporder', - name='dns_server', - field=models.ForeignKey(to='dhcp.DNSServer', related_name='server_group_order', on_delete=django.db.models.deletion.CASCADE), + model_name="dnsservergrouporder", + name="dns_server", + field=models.ForeignKey( + to="dhcp.DNSServer", + related_name="server_group_order", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterField( - model_name='dnsservergrouporder', - name='dns_server_group', - field=models.ForeignKey(to='dhcp.DNSServerGroup', related_name='server_group_order', on_delete=django.db.models.deletion.CASCADE), + model_name="dnsservergrouporder", + name="dns_server_group", + field=models.ForeignKey( + to="dhcp.DNSServerGroup", + related_name="server_group_order", + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/dhcp/migrations/0006_remove_dnsserver_is_default.py b/src/ralph/dhcp/migrations/0006_remove_dnsserver_is_default.py index 7bee8f756d..4b20b719a8 100644 --- a/src/ralph/dhcp/migrations/0006_remove_dnsserver_is_default.py +++ b/src/ralph/dhcp/migrations/0006_remove_dnsserver_is_default.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('dhcp', '0005_change_related_name'), + ("dhcp", "0005_change_related_name"), ] operations = [ migrations.RemoveField( - model_name='dnsserver', - name='is_default', + model_name="dnsserver", + name="is_default", ), ] diff --git a/src/ralph/dhcp/models.py b/src/ralph/dhcp/models.py index 60aa66c533..57d4b88b7a 100644 --- a/src/ralph/dhcp/models.py +++ b/src/ralph/dhcp/models.py @@ -8,14 +8,17 @@ class DHCPEntryManager(models.Manager): def get_queryset(self): - return super().get_queryset().select_related( - 'ethernet', 'ethernet__base_object' - ).filter( - hostname__isnull=False, - dhcp_expose=True, - ethernet__base_object__isnull=False, - ethernet__isnull=False, - ethernet__mac__isnull=False, + return ( + super() + .get_queryset() + .select_related("ethernet", "ethernet__base_object") + .filter( + hostname__isnull=False, + dhcp_expose=True, + ethernet__base_object__isnull=False, + ethernet__isnull=False, + ethernet__mac__isnull=False, + ) ) @@ -31,17 +34,15 @@ class Meta: class DHCPServer(AdminAbsoluteUrlMixin, models.Model): - ip = models.GenericIPAddressField( - verbose_name=_('IP address'), unique=True - ) + ip = models.GenericIPAddressField(verbose_name=_("IP address"), unique=True) network_environment = models.ForeignKey( NetworkEnvironment, null=True, blank=True, on_delete=models.CASCADE ) last_synchronized = models.DateTimeField(null=True, blank=True) class Meta: - verbose_name = _('DHCP Server') - verbose_name_plural = _('DHCP Servers') + verbose_name = _("DHCP Server") + verbose_name_plural = _("DHCP Servers") @classmethod def update_last_synchronized(cls, ip, time=None): @@ -51,38 +52,33 @@ def update_last_synchronized(cls, ip, time=None): class DNSServerGroup(NamedMixin, AdminAbsoluteUrlMixin, models.Model): - servers = models.ManyToManyField( - 'DNSServer', - through='DNSServerGroupOrder' - ) + servers = models.ManyToManyField("DNSServer", through="DNSServerGroupOrder") class Meta: - verbose_name = _('DNS Server Group') - verbose_name_plural = _('DNS Server Groups') + verbose_name = _("DNS Server Group") + verbose_name_plural = _("DNS Server Groups") def __str__(self): - servers = DNSServerGroupOrder.objects.select_related( - 'dns_server' - ).filter( - dns_server_group=self - ).values_list( - 'dns_server__ip_address', flat=True + servers = ( + DNSServerGroupOrder.objects.select_related("dns_server") + .filter(dns_server_group=self) + .values_list("dns_server__ip_address", flat=True) ) - return '{} ({})'.format(self.name, ', '.join(servers)) + return "{} ({})".format(self.name, ", ".join(servers)) class DNSServerGroupOrder(models.Model): dns_server_group = models.ForeignKey( - 'DNSServerGroup', related_name='server_group_order', on_delete=models.CASCADE + "DNSServerGroup", related_name="server_group_order", on_delete=models.CASCADE ) dns_server = models.ForeignKey( - 'DNSServer', related_name='server_group_order', on_delete=models.CASCADE + "DNSServer", related_name="server_group_order", on_delete=models.CASCADE ) order = models.PositiveIntegerField(editable=True, db_index=True) class Meta: - unique_together = (('dns_server_group', 'dns_server'),) - ordering = ('order',) + unique_together = (("dns_server_group", "dns_server"),) + ordering = ("order",) def __str__(self): return self.dns_server.ip_address @@ -90,13 +86,13 @@ def __str__(self): class DNSServer(AdminAbsoluteUrlMixin, models.Model): ip_address = models.GenericIPAddressField( - verbose_name=_('IP address'), + verbose_name=_("IP address"), unique=True, ) class Meta: - verbose_name = _('DNS Server') - verbose_name_plural = _('DNS Servers') + verbose_name = _("DNS Server") + verbose_name_plural = _("DNS Servers") def __str__(self): return self.ip_address diff --git a/src/ralph/dhcp/tests/factories.py b/src/ralph/dhcp/tests/factories.py index c68311fbef..afa7fbc283 100644 --- a/src/ralph/dhcp/tests/factories.py +++ b/src/ralph/dhcp/tests/factories.py @@ -1,30 +1,25 @@ import factory from factory.django import DjangoModelFactory -from ralph.dhcp.models import ( - DHCPServer, - DNSServer, - DNSServerGroup, - DNSServerGroupOrder -) +from ralph.dhcp.models import DHCPServer, DNSServer, DNSServerGroup, DNSServerGroupOrder class DNSServerFactory(DjangoModelFactory): - ip_address = factory.Faker('ipv4') + ip_address = factory.Faker("ipv4") class Meta: model = DNSServer class DHCPServerFactory(DjangoModelFactory): - ip = factory.Faker('ipv4') + ip = factory.Faker("ipv4") class Meta: model = DHCPServer class DNSServerGroupFactory(DjangoModelFactory): - name = factory.Faker('name') + name = factory.Faker("name") class Meta: model = DNSServerGroup diff --git a/src/ralph/dhcp/tests/test_agent.py b/src/ralph/dhcp/tests/test_agent.py index ac3b6f06ea..b0f03bdc41 100644 --- a/src/ralph/dhcp/tests/test_agent.py +++ b/src/ralph/dhcp/tests/test_agent.py @@ -13,18 +13,18 @@ default_params = { - 'dhcp_config_entries': None, - 'verbose': False, - 'proto': 'http', - 'log_path': 'STDOUT', - 'restart': None, - 'host': None, - 'dhcp_config_networks': None, - 'sections': ['entries'], - 'key': None, - 'dhcp_service_name': 'isc-dhcp-server', - 'dc': None, - 'net_env': None + "dhcp_config_entries": None, + "verbose": False, + "proto": "http", + "log_path": "STDOUT", + "restart": None, + "host": None, + "dhcp_config_networks": None, + "sections": ["entries"], + "key": None, + "dhcp_service_name": "isc-dhcp-server", + "dc": None, + "net_env": None, } @@ -32,67 +32,52 @@ class DHCPAgentTest(LiveServerTestCase): def setUp(self): self.user = get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' + "test", "test@test.test", "test" ) self.default_params = default_params.copy() - proto, host = self.live_server_url.split('://') - self.default_params.update({ - 'proto': proto, - 'host': host, - 'key': self.user.auth_token.key - }) + proto, host = self.live_server_url.split("://") + self.default_params.update( + {"proto": proto, "host": host, "key": self.user.auth_token.key} + ) @unpack @data( - ({'dc': 'fake-404,fake-dc', 'env': None},), - ({'dc': None, 'env': 'fake-env'},), + ({"dc": "fake-404,fake-dc", "env": None},), + ({"dc": None, "env": "fake-env"},), ) def test_get_configuration_should_return_false_when_dc_or_env_doesnt_exist( self, request_params ): params = self.default_params.copy() params.update(**request_params) - with Cache('/tmp/') as cache: - manager = DHCPConfigManager( - logger=logger, - cache=cache, - **params - ) - self.assertEqual( - manager._get_configuration(mode='entries'), - False - ) + with Cache("/tmp/") as cache: + manager = DHCPConfigManager(logger=logger, cache=cache, **params) + self.assertEqual(manager._get_configuration(mode="entries"), False) @unpack @data( - ('entries',), - ('networks',), + ("entries",), + ("networks",), ) def test_get_configuration_should_return_configuration(self, mode): dc = DataCenterFactory() params = self.default_params.copy() - params.update({ - 'dc': dc.name, - }) - with Cache('/tmp/') as cache: - manager = DHCPConfigManager( - logger=logger, - cache=cache, - **params - ) + params.update( + { + "dc": dc.name, + } + ) + with Cache("/tmp/") as cache: + manager = DHCPConfigManager(logger=logger, cache=cache, **params) data = manager._get_configuration(mode=mode) - self.assertTrue('config generated by Ralph' in data.decode()) + self.assertTrue("config generated by Ralph" in data.decode()) def test_agent_should_send_confirmation(self): - dc = DataCenterFactory() - dhcp_server = DHCPServer.objects.create( - ip='127.0.0.1', last_synchronized=None - ) - with Cache('/tmp/') as cache: + DataCenterFactory() + dhcp_server = DHCPServer.objects.create(ip="127.0.0.1", last_synchronized=None) + with Cache("/tmp/") as cache: manager = DHCPConfigManager( - logger=logger, - cache=cache, - **self.default_params + logger=logger, cache=cache, **self.default_params ) manager._send_sync_confirmation() dhcp_server.refresh_from_db() diff --git a/src/ralph/dhcp/tests/test_models.py b/src/ralph/dhcp/tests/test_models.py index 450a0c13e3..c1ccf85029 100644 --- a/src/ralph/dhcp/tests/test_models.py +++ b/src/ralph/dhcp/tests/test_models.py @@ -8,6 +8,5 @@ def test_dns_server_group_order_should_return_dns_server_ip_as_str(self): """__str__ from DNSServerGroupOrder is crucial for DHCP""" server_group_order = DNSServerGroupOrderFactory() self.assertEqual( - str(server_group_order.dns_server.ip_address), - str(server_group_order) + str(server_group_order.dns_server.ip_address), str(server_group_order) ) diff --git a/src/ralph/dhcp/tests/test_views.py b/src/ralph/dhcp/tests/test_views.py index af0dcc1a00..be18901b45 100644 --- a/src/ralph/dhcp/tests/test_views.py +++ b/src/ralph/dhcp/tests/test_views.py @@ -17,29 +17,27 @@ @ddt class DHCPConfigTest(TestCase): def test_config_endpoint_should_return_200(self): - get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' - ) - self.client.login(username='test', password='test') - network = NetworkFactory(address='192.168.1.0/24') - url = '{}?env={}'.format( - reverse('dhcp_config_entries'), network.network_environment + get_user_model().objects.create_superuser("test", "test@test.test", "test") + self.client.login(username="test", password="test") + network = NetworkFactory(address="192.168.1.0/24") + url = "{}?env={}".format( + reverse("dhcp_config_entries"), network.network_environment ) response = self.client.get(url) self.assertEqual(response.status_code, 200) def test_config_endpoint_should_return_401_when_user_is_anonymous(self): - network = NetworkFactory(address='192.168.1.0/24') - url = '{}?env={}'.format( - reverse('dhcp_config_entries'), network.network_environment + network = NetworkFactory(address="192.168.1.0/24") + url = "{}?env={}".format( + reverse("dhcp_config_entries"), network.network_environment ) response = self.client.get(url) self.assertEqual(response.status_code, 401) def test_config_endpoint_should_return_304(self): - network = NetworkFactory(address='192.168.1.0/24') - url = '{}?env={}'.format( - reverse('dhcp_config_entries'), network.network_environment + network = NetworkFactory(address="192.168.1.0/24") + url = "{}?env={}".format( + reverse("dhcp_config_entries"), network.network_environment ) response = self.client.get( url, HTTP_IF_MODIFIED_SINCE=http_date(network.modified.timestamp()) @@ -48,13 +46,11 @@ def test_config_endpoint_should_return_304(self): @unpack @data( - ('dc=foo&env=bar', 'Only DC or ENV mode available.'), - ('', 'Please specify DC or ENV.'), + ("dc=foo&env=bar", "Only DC or ENV mode available."), + ("", "Please specify DC or ENV."), ) def test_view_should_return_400(self, params, message): - url = '{}?{}'.format( - reverse('dhcp_config_entries'), params - ) + url = "{}?{}".format(reverse("dhcp_config_entries"), params) response = self.client.get(url) self.assertContains(response, message, status_code=400) @@ -64,69 +60,69 @@ def setUp(self): self.view = DHCPEntriesView() def test_dhcp_entries_are_returned_in_correct_format(self): - get_user_model().objects.create_superuser( - 'test', 'test@test.test', 'test' - ) - self.client.login(username='test', password='test') - network = NetworkFactory(address='192.168.1.0/24') - IPAddressFactory(address='192.168.1.2', dhcp_expose=True) - url = '{}?env={}'.format( - reverse('dhcp_config_entries'), network.network_environment + get_user_model().objects.create_superuser("test", "test@test.test", "test") + self.client.login(username="test", password="test") + network = NetworkFactory(address="192.168.1.0/24") + IPAddressFactory(address="192.168.1.2", dhcp_expose=True) + url = "{}?env={}".format( + reverse("dhcp_config_entries"), network.network_environment ) response = self.client.get(url) - lines = response.content.decode().strip().split('\n') - self.assertTrue(lines[0].startswith('# DHCP config generated by Ralph last modified at')) + lines = response.content.decode().strip().split("\n") + self.assertTrue( + lines[0].startswith("# DHCP config generated by Ralph last modified at") + ) self.assertTrue( re.match( - r'^host\s\S+\s\{fixed-address\s192\.168\.1\.2;\shardware\sethernet\s\S*?;\s}$', - lines[2] + r"^host\s\S+\s\{fixed-address\s192\.168\.1\.2;\shardware\sethernet\s\S*?;\s}$", + lines[2], ) ) self.assertEqual(len(lines), 4) def test_get_last_modified_should_return_ip_modified(self): - network = NetworkFactory(address='192.168.1.0/24') - ip = IPAddressFactory(address='192.168.1.2') + network = NetworkFactory(address="192.168.1.0/24") + ip = IPAddressFactory(address="192.168.1.2") returned = self.view.get_last_modified( Network.objects.filter(id__in=[network.id]) ) self.assertEqual( returned.strftime("%Y-%m-%d %H:%M:%S"), - ip.modified.strftime("%Y-%m-%d %H:%M:%S") + ip.modified.strftime("%Y-%m-%d %H:%M:%S"), ) def test_get_last_modified_should_return_network_modified(self): - network = NetworkFactory(address='192.168.1.0/24') - ip = IPAddressFactory(address='192.168.1.2') + network = NetworkFactory(address="192.168.1.0/24") + IPAddressFactory(address="192.168.1.2") network.save() returned = self.view.get_last_modified( Network.objects.filter(id__in=[network.id]) ) self.assertEqual( returned.strftime("%Y-%m-%d %H:%M:%S"), - network.modified.strftime("%Y-%m-%d %H:%M:%S") + network.modified.strftime("%Y-%m-%d %H:%M:%S"), ) def test_get_last_modified_should_return_ethernet_modified(self): - network = NetworkFactory(address='192.168.1.0/24') + network = NetworkFactory(address="192.168.1.0/24") ethernet = EthernetFactory() - ip = IPAddressFactory(address='192.168.1.2', ethernet=ethernet) + IPAddressFactory(address="192.168.1.2", ethernet=ethernet) ethernet.save() returned = self.view.get_last_modified( Network.objects.filter(id__in=[network.id]) ) self.assertEqual( returned.strftime("%Y-%m-%d %H:%M:%S"), - ethernet.modified.strftime("%Y-%m-%d %H:%M:%S") + ethernet.modified.strftime("%Y-%m-%d %H:%M:%S"), ) def test_get_last_modified_should_return_assets_ethernet_modified(self): - network = NetworkFactory(address='192.168.1.0/24') + network = NetworkFactory(address="192.168.1.0/24") asset = DataCenterAssetFactory() ethernet = EthernetFactory(base_object=asset) ethernet.save() - ip = IPAddressFactory( - address='192.168.1.2', base_object=asset, ethernet=ethernet + IPAddressFactory( + address="192.168.1.2", base_object=asset, ethernet=ethernet ) ethernet.save() returned = self.view.get_last_modified( @@ -134,36 +130,40 @@ def test_get_last_modified_should_return_assets_ethernet_modified(self): ) self.assertEqual( returned.strftime("%Y-%m-%d %H:%M:%S"), - ethernet.modified.strftime("%Y-%m-%d %H:%M:%S") + ethernet.modified.strftime("%Y-%m-%d %H:%M:%S"), ) def test_get_last_modified_should_run_5_queries(self): - network = NetworkFactory(address='192.168.1.0/24') + network = NetworkFactory(address="192.168.1.0/24") with self.assertNumQueries(5): - self.view.get_last_modified( - Network.objects.filter(id__in=[network.id]) - ) + self.view.get_last_modified(Network.objects.filter(id__in=[network.id])) def test_filter_duplicated_hostnames(self): - network = NetworkFactory(address='192.168.1.0/24') + network = NetworkFactory(address="192.168.1.0/24") asset = DataCenterAssetFactory() ethernet = EthernetFactory(base_object=asset) ethernet.save() IPAddressFactory( - hostname='host1.mydc.net', address='192.168.1.2', ethernet=ethernet, - dhcp_expose=True + hostname="host1.mydc.net", + address="192.168.1.2", + ethernet=ethernet, + dhcp_expose=True, ) ethernet2 = EthernetFactory() ethernet2.save() IPAddressFactory( - hostname='host1.mydc.net', address='192.168.1.3', - ethernet=ethernet2, dhcp_expose=True + hostname="host1.mydc.net", + address="192.168.1.3", + ethernet=ethernet2, + dhcp_expose=True, ) ethernet3 = EthernetFactory() ethernet3.save() ip = IPAddressFactory( - hostname='host2.mydc.net', address='192.168.1.4', - ethernet=ethernet3, dhcp_expose=True + hostname="host2.mydc.net", + address="192.168.1.4", + ethernet=ethernet3, + dhcp_expose=True, ) entries = self.view._get_dhcp_entries( Network.objects.filter(id__in=[network.id]) diff --git a/src/ralph/dhcp/urls.py b/src/ralph/dhcp/urls.py index dd81570f00..5f3ee0b585 100644 --- a/src/ralph/dhcp/urls.py +++ b/src/ralph/dhcp/urls.py @@ -3,19 +3,7 @@ from ralph.dhcp.views import DHCPEntriesView, DHCPNetworksView, DHCPSyncView urlpatterns = [ - url( - r'^sync/?$', - DHCPSyncView.as_view(), - name='dhcp_config_sync' - ), - url( - r'^entries/?$', - DHCPEntriesView.as_view(), - name='dhcp_config_entries' - ), - url( - r'^networks/?$', - DHCPNetworksView.as_view(), - name='dhcp_config_networks' - ), + url(r"^sync/?$", DHCPSyncView.as_view(), name="dhcp_config_sync"), + url(r"^entries/?$", DHCPEntriesView.as_view(), name="dhcp_config_entries"), + url(r"^networks/?$", DHCPNetworksView.as_view(), name="dhcp_config_networks"), ] diff --git a/src/ralph/dhcp/views.py b/src/ralph/dhcp/views.py index 1135505a3d..497e23a9bc 100644 --- a/src/ralph/dhcp/views.py +++ b/src/ralph/dhcp/views.py @@ -5,7 +5,7 @@ HttpResponse, HttpResponseBadRequest, HttpResponseNotFound, - HttpResponseNotModified + HttpResponseNotModified, ) from django.utils.http import http_date, parse_http_date_safe from django.views.generic.base import TemplateView @@ -16,11 +16,7 @@ from ralph.data_center.models import DataCenter from ralph.deployment.models import Deployment from ralph.dhcp.models import DHCPEntry, DHCPServer, DNSServer -from ralph.networks.models.networks import ( - IPAddress, - Network, - NetworkEnvironment -) +from ralph.networks.models.networks import IPAddress, Network, NetworkEnvironment logger = logging.getLogger(__name__) @@ -29,7 +25,7 @@ def last_modified_date(qs, filter_dict=None): last_date = None if filter_dict is None: filter_dict = {} - obj = qs.filter(**filter_dict).order_by('-modified').first() + obj = qs.filter(**filter_dict).order_by("-modified").first() if obj: last_date = obj.modified return last_date @@ -40,11 +36,11 @@ class LastModifiedMixin(object): @property def last_timestamp(self): - last_modified = getattr(self, 'last_modified', None) + last_modified = getattr(self, "last_modified", None) return last_modified and int(last_modified.timestamp()) def is_modified(self, request): - http_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE') + http_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE") if http_modified_since is None or self.last_timestamp is None: return True return self.last_timestamp > parse_http_date_safe(http_modified_since) @@ -53,12 +49,12 @@ def dispatch(self, request, *args, **kwargs): response = super().dispatch(request, *args, **kwargs) if not self.is_modified(request): return HttpResponseNotModified() - response['Last-Modified'] = http_date(self.last_timestamp) + response["Last-Modified"] = http_date(self.last_timestamp) return response class DHCPConfigMixin(object): - content_type = 'text/plain' + content_type = "text/plain" @staticmethod def check_objects_existence_by_names(model_class, names): @@ -67,18 +63,16 @@ def check_objects_existence_by_names(model_class, names): return found, not_found def dispatch(self, request, *args, **kwargs): - dc_names = request.GET.getlist('dc', None) - env_names = request.GET.getlist('env', None) + dc_names = request.GET.getlist("dc", None) + env_names = request.GET.getlist("env", None) if dc_names and env_names: return HttpResponseBadRequest( - 'Only DC or ENV mode available.', - content_type=self.content_type + "Only DC or ENV mode available.", content_type=self.content_type ) if not (dc_names or env_names): return HttpResponseBadRequest( - 'Please specify DC or ENV.', - content_type=self.content_type + "Please specify DC or ENV.", content_type=self.content_type ) if dc_names: @@ -87,26 +81,22 @@ def dispatch(self, request, *args, **kwargs): ) if not_found: return HttpResponseNotFound( - 'DC: {} doesn\'t exists.'.format(', '.join(not_found)), - content_type='text/plain' + "DC: {} doesn't exists.".format(", ".join(not_found)), + content_type="text/plain", ) - environments = NetworkEnvironment.objects.filter( - data_center__in=found - ) + environments = NetworkEnvironment.objects.filter(data_center__in=found) elif env_names: found, not_found = self.check_objects_existence_by_names( NetworkEnvironment, env_names ) if not_found: return HttpResponseNotFound( - 'ENV: {} doesn\'t exists.'.format(', '.join(not_found)), - content_type='text/plain' + "ENV: {} doesn't exists.".format(", ".join(not_found)), + content_type="text/plain", ) environments = found - self.networks = Network.objects.select_related( - 'network_environment' - ).filter( + self.networks = Network.objects.select_related("network_environment").filter( network_environment__in=environments, dhcp_broadcast=True, ) @@ -117,19 +107,17 @@ def dispatch(self, request, *args, **kwargs): class DHCPSyncView(APIView): def get(self, request, *args, **kwargs): ip = get_client_ip(request) - logger.info('Sync request DHCP server with IP: %s', ip) + logger.info("Sync request DHCP server with IP: %s", ip) if not DHCPServer.update_last_synchronized(ip): return HttpResponseNotFound( - 'DHCP server doesn\'t exist.', content_type='text/plain' + "DHCP server doesn't exist.", content_type="text/plain" ) - return HttpResponse('OK', content_type='text/plain') + return HttpResponse("OK", content_type="text/plain") -class DHCPEntriesView( - DHCPConfigMixin, LastModifiedMixin, TemplateView, APIView -): - http_method_names = ['get'] - template_name = 'dhcp/entries.conf' +class DHCPEntriesView(DHCPConfigMixin, LastModifiedMixin, TemplateView, APIView): + http_method_names = ["get"] + template_name = "dhcp/entries.conf" def get_last_modified(self, networks): """ @@ -139,24 +127,20 @@ def get_last_modified(self, networks): last_items = [] try: - last_items.append(Deployment.objects.latest('modified').modified) + last_items.append(Deployment.objects.latest("modified").modified) except Deployment.DoesNotExist: pass last_items.append(last_modified_date(networks)) last_items.append( - last_modified_date(DHCPEntry.objects, filter_dict={ - 'network__in': networks - }) + last_modified_date(DHCPEntry.objects, filter_dict={"network__in": networks}) ) last_items.append( - last_modified_date(Ethernet.objects, filter_dict={ - 'ipaddress__network__in': networks - }) + last_modified_date( + Ethernet.objects, filter_dict={"ipaddress__network__in": networks} + ) ) last_items.append( - last_modified_date(IPAddress.objects, filter_dict={ - 'network__in': networks - }) + last_modified_date(IPAddress.objects, filter_dict={"network__in": networks}) ) last_items = [item for item in last_items if item is not None] if not last_items: @@ -167,50 +151,49 @@ def _filter_dhcp_entries(self, entries): """ Exclude entries with duplicated hostnames. """ - duplicated_hostnames = [e['hostname'] for e in entries.values( - 'hostname' - ).annotate(c=Count('id')).filter(c__gt=1)] + duplicated_hostnames = [ + e["hostname"] + for e in entries.values("hostname").annotate(c=Count("id")).filter(c__gt=1) + ] for hostname in duplicated_hostnames: - logger.error( - 'Duplicated hostname for DHCP entry: %s', hostname - ) + logger.error("Duplicated hostname for DHCP entry: %s", hostname) return entries.exclude(hostname__in=duplicated_hostnames) def _get_dhcp_entries(self, networks): """ Returns filtered DHCP entries for given networks. """ - return self._filter_dhcp_entries(DHCPEntry.objects.filter( - network__in=networks - ).order_by('hostname')) + return self._filter_dhcp_entries( + DHCPEntry.objects.filter(network__in=networks).order_by("hostname") + ) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context.update({ - 'last_modified': self.last_modified, - 'entries': self._get_dhcp_entries(self.networks), - }) + context.update( + { + "last_modified": self.last_modified, + "entries": self._get_dhcp_entries(self.networks), + } + ) return context -class DHCPNetworksView( - DHCPConfigMixin, LastModifiedMixin, TemplateView, APIView -): - template_name = 'dhcp/networks.conf' +class DHCPNetworksView(DHCPConfigMixin, LastModifiedMixin, TemplateView, APIView): + template_name = "dhcp/networks.conf" def get_last_modified(self, networks): last_items = [] last_items.append(last_modified_date(networks)) last_items.append( - last_modified_date(NetworkEnvironment.objects, filter_dict={ - 'network__in': networks - }) + last_modified_date( + NetworkEnvironment.objects, filter_dict={"network__in": networks} + ) ) last_items.append( - last_modified_date(IPAddress.objects, filter_dict={ - 'network__in': networks, - 'is_gateway': True - }) + last_modified_date( + IPAddress.objects, + filter_dict={"network__in": networks, "is_gateway": True}, + ) ) last_items = [item for item in last_items if item is not None] if not last_items: @@ -219,25 +202,27 @@ def get_last_modified(self, networks): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - networks = self.networks.filter( - network_environment__domain__isnull=False, - dhcp_broadcast=True, - gateway__isnull=False, - ).exclude( - network_environment=False - ).select_related( - 'dns_servers_group', - 'gateway' - ).prefetch_related( - Prefetch( - 'dns_servers_group__server_group_order__dns_server', - queryset=DNSServer.objects.all().order_by( - 'server_group_order__order' + networks = ( + self.networks.filter( + network_environment__domain__isnull=False, + dhcp_broadcast=True, + gateway__isnull=False, + ) + .exclude(network_environment=False) + .select_related("dns_servers_group", "gateway") + .prefetch_related( + Prefetch( + "dns_servers_group__server_group_order__dns_server", + queryset=DNSServer.objects.all().order_by( + "server_group_order__order" + ), ) ) ) - context.update({ - 'last_modified': self.last_modified, - 'entries': networks, - }) + context.update( + { + "last_modified": self.last_modified, + "entries": networks, + } + ) return context diff --git a/src/ralph/dns/__init__.py b/src/ralph/dns/__init__.py index 12f0bb19b2..d2017aeec3 100644 --- a/src/ralph/dns/__init__.py +++ b/src/ralph/dns/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.dns.apps.DNS' +default_app_config = "ralph.dns.apps.DNS" diff --git a/src/ralph/dns/apps.py b/src/ralph/dns/apps.py index 560c68d1de..3b84e8a3b8 100644 --- a/src/ralph/dns/apps.py +++ b/src/ralph/dns/apps.py @@ -3,10 +3,9 @@ class DNS(RalphAppConfig): - - name = 'ralph.dns' + name = "ralph.dns" def get_load_modules_when_ready(self): if settings.ENABLE_HERMES_INTEGRATION: - return ['publishers'] + return ["publishers"] return [] diff --git a/src/ralph/dns/dnsaas.py b/src/ralph/dns/dnsaas.py index 0bc8a1d643..ce5b3bff83 100644 --- a/src/ralph/dns/dnsaas.py +++ b/src/ralph/dns/dnsaas.py @@ -4,7 +4,7 @@ from datetime import datetime, timedelta from functools import wraps from typing import List, Optional, Tuple, Union -from urllib.parse import parse_qs, urlencode, urljoin, urlsplit +from urllib.parse import parse_qs, urlencode, urljoin, urlsplit import requests from dj.choices import Choices from django.conf import settings @@ -21,9 +21,9 @@ class RecordType(Choices): _ = Choices.Choice - a = _('A') - txt = _('TXT') - cname = _('CNAME') + a = _("A") + txt = _("TXT") + cname = _("CNAME") def renew_token_when_unauthorized(func): @@ -35,17 +35,17 @@ def wrapper(self, *args, **kwargs): self._update_oauth_token() status_code, data = func(self, *args, **kwargs) return status_code, data + return wrapper class DNSaaS: - def __init__(self, headers: dict = None): self.session = requests.Session() _headers = { - 'Content-Type': 'application/json', - 'User-agent': 'Ralph/DNSaaS/Client', - 'Authorization': 'Bearer {}'.format(self._get_oauth_token()) + "Content-Type": "application/json", + "User-agent": "Ralph/DNSaaS/Client", + "Authorization": "Bearer {}".format(self._get_oauth_token()), } if headers is not None: _headers.update(headers) @@ -64,21 +64,22 @@ def _get_oauth_token(self): except CustomOAuth2Error as e: logger.error(str(e)) - expire_in = token.get('expires_in') + expire_in = token.get("expires_in") self.token_expiration = datetime.now() + timedelta(0, expire_in - 60) - return token.get('access_token') + return token.get("access_token") def _update_oauth_token(self): token = self._get_oauth_token() - self.session.headers['Authorization'] = 'Bearer {}'.format(token) + self.session.headers["Authorization"] = "Bearer {}".format(token) def _verify_oauth_token_validity(self): if datetime.now() >= self.token_expiration: self._update_oauth_token() @staticmethod - def build_url(resource_name: str, id: int = None, - get_params: QueryParams = None) -> str: + def build_url( + resource_name: str, id: int = None, get_params: QueryParams = None + ) -> str: """ Return Url for DNSAAS endpoint @@ -91,21 +92,18 @@ def build_url(resource_name: str, id: int = None, Returns: string url """ - result_url = urljoin( - settings.DNSAAS_URL, - 'api/{}/'.format(resource_name) - ) + result_url = urljoin(settings.DNSAAS_URL, "api/{}/".format(resource_name)) if id: - result_url = '{}{}/'.format(result_url, str(id)) + result_url = "{}{}/".format(result_url, str(id)) if get_params: - result_url = '{}?{}'.format(result_url, urlencode(get_params)) + result_url = "{}?{}".format(result_url, urlencode(get_params)) return result_url @staticmethod def _set_page_qp(url: str, page: int): _url = urlsplit(url) qp = parse_qs(_url.query) - qp['page'] = page + qp["page"] = page query = urlencode(qp, doseq=True) result_url = _url._replace(query=query).geturl() return result_url @@ -132,8 +130,8 @@ def get_api_result(self, url: str) -> List[dict]: def _get_api_result(self, url: str) -> Tuple[List[dict], bool]: status_code, json_data = self._get(url) - api_results = json_data.get('content', []) - last_page = bool(json_data.get('last', False)) + api_results = json_data.get("content", []) + last_page = bool(json_data.get("last", False)) return api_results, last_page def get_dns_records(self, ipaddresses: List[str]) -> List[dict]: @@ -141,25 +139,30 @@ def get_dns_records(self, ipaddresses: List[str]) -> List[dict]: dns_records = [] if not ipaddresses: return [] - ipaddresses = [('ip', i) for i in ipaddresses] + ipaddresses = [("ip", i) for i in ipaddresses] url = self.build_url( - 'records', - get_params=[('size', '100'), ] + ipaddresses + "records", + get_params=[ + ("size", "100"), + ] + + ipaddresses, ) api_results = self.get_api_result(url) - ptrs = set([i['content'] for i in api_results if i['type'] == 'PTR']) + ptrs = set([i["content"] for i in api_results if i["type"] == "PTR"]) for item in api_results: - if item['type'] in {'A', 'CNAME', 'TXT'}: - dns_records.append({ - 'pk': item['id'], - 'name': item['name'], - 'type': RecordType.from_name(item['type'].lower()).id, - 'content': item['content'], - 'ptr': item['name'] in ptrs and item['type'] == 'A', - 'owner': settings.DNSAAS_OWNER - }) - return sorted(dns_records, key=lambda x: x['type']) + if item["type"] in {"A", "CNAME", "TXT"}: + dns_records.append( + { + "pk": item["id"], + "name": item["name"], + "type": RecordType.from_name(item["type"].lower()).id, + "content": item["content"], + "ptr": item["name"] in ptrs and item["type"] == "A", + "owner": settings.DNSAAS_OWNER, + } + ) + return sorted(dns_records, key=lambda x: x["type"]) def update_dns_record(self, record: dict) -> Optional[dict]: """ @@ -171,11 +174,11 @@ def update_dns_record(self, record: dict) -> Optional[dict]: Returns: Validation error from API or None if update correct """ - url = self.build_url('records', id=record['pk']) + url = self.build_url("records", id=record["pk"]) data = { - 'name': record['name'], - 'type': RecordType.raw_from_id(int(record['type'])), - 'content': record['content'], + "name": record["name"], + "type": RecordType.raw_from_id(int(record["type"])), + "content": record["content"], } status_code, response_data = self._patch(url, data) @@ -183,15 +186,10 @@ def update_dns_record(self, record: dict) -> Optional[dict]: return response_data @staticmethod - def _response2result( - response: requests.Response - ) -> Union[dict, list, None]: + def _response2result(response: requests.Response) -> Union[dict, list, None]: if response.status_code == 500: - logger.error('Internal Server Error from DNSAAS: %s', - response.content) - return { - 'non_field_errors': ['Internal Server Error from DNSAAS'] - } + logger.error("Internal Server Error from DNSAAS: %s", response.content) + return {"non_field_errors": ["Internal Server Error from DNSAAS"]} elif response.status_code not in (202, 204): try: return response.json() @@ -210,54 +208,53 @@ def create_dns_record(self, record: dict, service=None) -> Optional[dict]: Validation error from API or None if create correct """ - url = self.build_url('records') + url = self.build_url("records") data = { - 'name': record['name'], - 'type': RecordType.raw_from_id(int(record['type'])), - 'content': record['content'], + "name": record["name"], + "type": RecordType.raw_from_id(int(record["type"])), + "content": record["content"], } if service: - data['service_uid'] = service.uid + data["service_uid"] = service.uid else: - logger.error( - 'Service is required for record %s', data - ) - return {'errors': [{ - 'value': 'name', - 'comment': _('Service is required for record {}'.format(data)) - }]} + logger.error("Service is required for record %s", data) + return { + "errors": [ + { + "value": "name", + "comment": _("Service is required for record {}".format(data)), + } + ] + } return self._post(url, data)[1] - def _send_request_to_dnsaas(self, request_method: str, url: str, - json_data: dict = None) -> requests.Response: + def _send_request_to_dnsaas( + self, request_method: str, url: str, json_data: dict = None + ) -> requests.Response: try: response = self.session.request( method=request_method, url=url, json=json_data, - timeout=float(settings.DNSAAS_TIMEOUT) + timeout=float(settings.DNSAAS_TIMEOUT), ) logger.info( - 'Sent {} request to DNSaaS to {}'.format( - request_method, url - ), + "Sent {} request to DNSaaS to {}".format(request_method, url), extra={ - 'request_data': json.dumps(json_data), - 'response_status': response.status_code, - 'response_content': response.text - } + "request_data": json.dumps(json_data), + "response_status": response.status_code, + "response_content": response.text, + }, ) return response except Exception: logger.exception( - 'Sending {} request to DNSaaS to {} failed.'.format( + "Sending {} request to DNSaaS to {} failed.".format( request_method, url ), - extra={ - 'request_data': json.dumps(json_data) - } + extra={"request_data": json.dumps(json_data)}, ) raise @@ -273,24 +270,24 @@ def _post(self, url: str, data: dict) -> [int, Optional[dict]]: Returns: tuple (response status code, dict data) """ - response = self._send_request_to_dnsaas('POST', url, json_data=data) + response = self._send_request_to_dnsaas("POST", url, json_data=data) return response.status_code, self._response2result(response) @renew_token_when_unauthorized def _delete(self, url: str) -> [int, Optional[dict]]: - response = self._send_request_to_dnsaas('DELETE', url) + response = self._send_request_to_dnsaas("DELETE", url) return response.status_code, self._response2result(response) @renew_token_when_unauthorized def _get(self, url: str) -> [int, Optional[dict]]: - response = self._send_request_to_dnsaas('GET', url) + response = self._send_request_to_dnsaas("GET", url) return response.status_code, self._response2result(response) @renew_token_when_unauthorized def _patch(self, url: str, data: dict) -> [int, Optional[dict]]: - response = self._send_request_to_dnsaas('PATCH', url, json_data=data) + response = self._send_request_to_dnsaas("PATCH", url, json_data=data) return response.status_code, self._response2result(response) def delete_dns_record(self, record_id: int) -> dict: @@ -303,7 +300,7 @@ def delete_dns_record(self, record_id: int) -> dict: Returns: Validation error from API or None if delete correct """ - url = self.build_url('records', id=record_id) + url = self.build_url("records", id=record_id) _, data = self._delete(url) return data @@ -334,11 +331,13 @@ def send_ipaddress_data(self, ip_record_data: dict): Returns: JSON response from API """ - logger.info('Send update data: {}'.format(ip_record_data)) - url = self.build_url('ip-record') + logger.info("Send update data: {}".format(ip_record_data)) + url = self.build_url("ip-record") status_code, response_data = self._post(url, ip_record_data) if status_code >= 400: logger.error( - 'DNSaaS returned %s data: %s, send_data: %s', - status_code, str(response_data), ip_record_data + "DNSaaS returned %s data: %s, send_data: %s", + status_code, + str(response_data), + ip_record_data, ) diff --git a/src/ralph/dns/forms.py b/src/ralph/dns/forms.py index 108e70a5c8..fa8d9cdf85 100644 --- a/src/ralph/dns/forms.py +++ b/src/ralph/dns/forms.py @@ -7,51 +7,45 @@ class RecordType(Choices): _ = Choices.Choice - a = _('A') - txt = _('TXT') - cname = _('CNAME') + a = _("A") + txt = _("TXT") + cname = _("CNAME") class DNSRecordForm(forms.Form): - - pk = forms.IntegerField( - label='', - widget=forms.HiddenInput(), - required=False - ) + pk = forms.IntegerField(label="", widget=forms.HiddenInput(), required=False) name = forms.CharField( - label=_('Name'), + label=_("Name"), max_length=255, help_text=_( - 'Actual name of a record. Must not end in a \'.\' and be' - ' fully qualified - it is not relative to the name of the' - ' domain!' - ) + "Actual name of a record. Must not end in a '.' and be" + " fully qualified - it is not relative to the name of the" + " domain!" + ), ) type = forms.ChoiceField( label=_("Record type"), choices=RecordType(), ) content = forms.CharField( - label=_('Content'), + label=_("Content"), max_length=255, help_text=_( - 'The \'right hand side\' of a DNS record. For an A' - ' record, this is the IP address' + "The 'right hand side' of a DNS record. For an A" + " record, this is the IP address" ), - widget=forms.TextInput(attrs={'style': 'width:300px;'}) + widget=forms.TextInput(attrs={"style": "width:300px;"}), ) ptr = forms.BooleanField( - label=_('PTR'), + label=_("PTR"), initial=False, required=False, - widget=forms.CheckboxInput(attrs={'disabled': True}) + widget=forms.CheckboxInput(attrs={"disabled": True}), ) def clean(self): cleaned_data = super().clean() - if ( - cleaned_data.get('ptr', False) and - cleaned_data.get('type', None) != str(RecordType.a.id) + if cleaned_data.get("ptr", False) and cleaned_data.get("type", None) != str( + RecordType.a.id ): - raise forms.ValidationError(_('Only A type record can be PTR')) + raise forms.ValidationError(_("Only A type record can be PTR")) diff --git a/src/ralph/dns/management/commands/dns_find_inconsistencies.py b/src/ralph/dns/management/commands/dns_find_inconsistencies.py index aebd372cf0..fbe1908b2c 100644 --- a/src/ralph/dns/management/commands/dns_find_inconsistencies.py +++ b/src/ralph/dns/management/commands/dns_find_inconsistencies.py @@ -31,16 +31,16 @@ def get_ptr(ip): """ ip_obj = ipaddress.ip_address(ip) if isinstance(ip_obj, ipaddress.IPv6Address): - reverse_chars = ip_obj.exploded[::-1].replace(':', '') - rev_ptr = '.'.join(reverse_chars) + '.ip6.arpa' + reverse_chars = ip_obj.exploded[::-1].replace(":", "") + rev_ptr = ".".join(reverse_chars) + ".ip6.arpa" else: - reverse_octets = str(ip_obj).split('.')[::-1] - rev_ptr = '.'.join(reverse_octets) + '.in-addr.arpa' + reverse_octets = str(ip_obj).split(".")[::-1] + rev_ptr = ".".join(reverse_octets) + ".in-addr.arpa" return rev_ptr class Command(BaseCommand): - help = 'Compare DNS records in DNSaaS with state of IP-hostname in Ralph' + help = "Compare DNS records in DNSaaS with state of IP-hostname in Ralph" # TODO (mkurek): add possibility to exclude some domains @@ -87,21 +87,20 @@ def _fetch_dns_records(self): ) """ url = self.dns.build_url( - 'records', + "records", get_params=[ - ('limit', 1000), - ('offset', 0), - ] + [('type', t) for t in {'A', 'PTR'}] + ("limit", 1000), + ("offset", 0), + ] + + [("type", t) for t in {"A", "PTR"}], ) api_results = self.dns.get_api_result(url) records_by_types = defaultdict(lambda: defaultdict(list)) records_by_types_rev = defaultdict(lambda: defaultdict(list)) for record in api_results: - records_by_types[record['type']][record['name']].append( - record['content'] - ) - records_by_types_rev[record['type']][record['content']].append( - record['name'] + records_by_types[record["type"]][record["name"]].append(record["content"]) + records_by_types_rev[record["type"]][record["content"]].append( + record["name"] ) return records_by_types, records_by_types_rev @@ -110,9 +109,8 @@ def _get_ips(self): Return dict with IP-hostname from Ralph. """ ips = IPAddress.objects.filter( - ethernet__base_object__cloudhost__isnull=True, - hostname__isnull=False - ).values_list('address', 'hostname') + ethernet__base_object__cloudhost__isnull=True, hostname__isnull=False + ).values_list("address", "hostname") return dict(ips) def get_missing_a_records_in_dnsaas(self, ips, dns, dns_rev): @@ -121,7 +119,7 @@ def get_missing_a_records_in_dnsaas(self, ips, dns, dns_rev): DNSaaS """ for ip, hostname in ips.items(): - if ip not in dns_rev['A']: + if ip not in dns_rev["A"]: yield (ip, hostname) def get_wrong_a_records_in_dnsaas(self, ips, dns, dns_rev): @@ -130,8 +128,8 @@ def get_wrong_a_records_in_dnsaas(self, ips, dns, dns_rev): are both in Ralph and DNSaaS, but are inconsistent """ for ip, hostname in ips.items(): - if ip in dns_rev['A']: - dns_hostnames = dns_rev['A'][ip] + if ip in dns_rev["A"]: + dns_hostnames = dns_rev["A"][ip] if hostname not in dns_hostnames or len(dns_hostnames) != 1: yield (ip, hostname, dns_hostnames) @@ -140,7 +138,7 @@ def get_missing_a_records_in_ralph(self, ips, dns, dns_rev): Return pairs of (ip, list of hostnames) for Records (ips) which are present in DNSaaS, but they are not in Ralph. """ - for ip, hostnames in dns_rev['A'].items(): + for ip, hostnames in dns_rev["A"].items(): if ip not in ips: yield (ip, hostnames) @@ -150,20 +148,20 @@ def check_ralph_ptrs(self, ips, dns, dns_rev): records. """ for ip, hostname in ips.items(): - if ip in dns_rev['A'] and hostname in dns_rev['A'][ip]: + if ip in dns_rev["A"] and hostname in dns_rev["A"][ip]: ptr = get_ptr(ip) - if ptr not in dns['PTR'] or hostname not in dns['PTR'][ptr]: - yield (ip, hostname, dns['PTR'].get(ptr)) + if ptr not in dns["PTR"] or hostname not in dns["PTR"][ptr]: + yield (ip, hostname, dns["PTR"].get(ptr)) def get_zombie_ptrs(self, ips, dns, dns_rev): """ Return pairs of (ip, hostname) which has not properly configured PTR records. """ - for hostname, ptrs in dns_rev['PTR'].items(): + for hostname, ptrs in dns_rev["PTR"].items(): for ptr in ptrs: - ip = '.'.join(ptr.split('.')[3::-1]) - if hostname not in dns['A'] or ip not in dns['A'][hostname]: + ip = ".".join(ptr.split(".")[3::-1]) + if hostname not in dns["A"] or ip not in dns["A"][hostname]: yield ptr, hostname def get_duplicated_ptrs(self, ips, dns, dns_rev): @@ -171,7 +169,7 @@ def get_duplicated_ptrs(self, ips, dns, dns_rev): Return pairs of (ip, hostname) which has not properly configured PTR records. """ - for ptr, hostnames in dns['PTR'].items(): + for ptr, hostnames in dns["PTR"].items(): if len(hostnames) > 1: yield ptr, hostnames @@ -181,40 +179,32 @@ def handle(self, **options): for func, headers, description in [ ( self.get_missing_a_records_in_dnsaas, - ['IP', 'hostname'], - 'A records missing in DNSaaS' + ["IP", "hostname"], + "A records missing in DNSaaS", ), ( self.get_missing_a_records_in_ralph, - ['IP', 'hostname'], - 'A records missing in Ralph' + ["IP", "hostname"], + "A records missing in Ralph", ), ( self.get_wrong_a_records_in_dnsaas, - ['IP', 'ralph hostname', 'dnsaas hostnames'], - 'Inconsistent A records' + ["IP", "ralph hostname", "dnsaas hostnames"], + "Inconsistent A records", ), ( self.check_ralph_ptrs, - ['IP', 'ralph hostname', 'PTR content'], - 'Missing or wrong PTR records' - ), - ( - self.get_zombie_ptrs, - ['PTR', 'hostname (content)'], - 'Zombie PTR records' - ), - ( - self.get_duplicated_ptrs, - ['PTR', 'hostnames'], - 'Duplicated PTR records' + ["IP", "ralph hostname", "PTR content"], + "Missing or wrong PTR records", ), + (self.get_zombie_ptrs, ["PTR", "hostname (content)"], "Zombie PTR records"), + (self.get_duplicated_ptrs, ["PTR", "hostnames"], "Duplicated PTR records"), ]: result = func(ips, dns, dns_rev) - self.stdout.write(TEMPLATE.format( - description=description, - headers='\t'.join(headers), - content='\n'.join( - ['\t'.join(map(str, line)) for line in result] - ), - )) + self.stdout.write( + TEMPLATE.format( + description=description, + headers="\t".join(headers), + content="\n".join(["\t".join(map(str, line)) for line in result]), + ) + ) diff --git a/src/ralph/dns/publishers.py b/src/ralph/dns/publishers.py index e397a05de7..1f7f9e52c9 100644 --- a/src/ralph/dns/publishers.py +++ b/src/ralph/dns/publishers.py @@ -16,23 +16,23 @@ def _get_txt_data_to_publish_to_dnsaas(obj): publish_data = [] for data in obj.get_auto_txt_data(): - data['owner'] = settings.DNSAAS_OWNER - data['target_owner'] = settings.DNSAAS_OWNER + data["owner"] = settings.DNSAAS_OWNER + data["target_owner"] = settings.DNSAAS_OWNER publish_data.append(data) return publish_data @pyhermes.publisher( - topic=settings.DNSAAS_AUTO_TXT_RECORD_TOPIC_NAME or '', + topic=settings.DNSAAS_AUTO_TXT_RECORD_TOPIC_NAME or "", # call publish directly to make testing (overriding settings) easier auto_publish_result=False, ) def publish_data_to_dnsaaas(obj): if settings.DNSAAS_AUTO_TXT_RECORD_TOPIC_NAME: - logger.info('Publishing DNS TXT records update for {}'.format(obj)) + logger.info("Publishing DNS TXT records update for {}".format(obj)) publish( settings.DNSAAS_AUTO_TXT_RECORD_TOPIC_NAME, - _get_txt_data_to_publish_to_dnsaas(obj) + _get_txt_data_to_publish_to_dnsaas(obj), ) diff --git a/src/ralph/dns/tests.py b/src/ralph/dns/tests.py index ac5ec3f152..504e3cf7a3 100644 --- a/src/ralph/dns/tests.py +++ b/src/ralph/dns/tests.py @@ -4,91 +4,73 @@ from django.db import transaction from django.test import override_settings, TestCase, TransactionTestCase -from ralph.assets.tests.factories import ( - ConfigurationClassFactory, - EthernetFactory -) +from ralph.assets.tests.factories import ConfigurationClassFactory, EthernetFactory from ralph.data_center.models import BaseObjectCluster, DataCenterAsset from ralph.dns.dnsaas import DNSaaS from ralph.dns.forms import DNSRecordForm, RecordType from ralph.dns.publishers import _get_txt_data_to_publish_to_dnsaas -from ralph.dns.views import ( - add_errors, - DNSaaSIntegrationNotEnabledError, - DNSView -) +from ralph.dns.views import add_errors, DNSaaSIntegrationNotEnabledError, DNSView from ralph.networks.tests.factories import IPAddressFactory from ralph.virtual.models import VirtualServer from ralph.virtual.tests.factories import VirtualServerFactory class TestGetDnsRecords(TestCase): - - @patch.object(DNSaaS, '_get_oauth_token') + @patch.object(DNSaaS, "_get_oauth_token") def setUp(self, mocked): - mocked.return_value = 'token' + mocked.return_value = "token" self.dnsaas = DNSaaS() - @patch.object(DNSaaS, 'get_api_result') + @patch.object(DNSaaS, "get_api_result") def test_return_empty_when_api_returns_empty(self, mocked): mocked.return_value = [] - found_dns = self.dnsaas.get_dns_records(['192.168.0.1']) + found_dns = self.dnsaas.get_dns_records(["192.168.0.1"]) self.assertEqual(found_dns, []) def test_return_empty_when_no_ipaddress(self): found_dns = self.dnsaas.get_dns_records([]) self.assertEqual(found_dns, []) - @patch.object(DNSaaS, 'get_api_result') + @patch.object(DNSaaS, "get_api_result") def test_return_dns_records_when_api_returns_records(self, mocked): - data = { - 'content': '127.0.0.3', - 'name': '1.test.pl', - 'type': 'A', - 'id': 1 - } + data = {"content": "127.0.0.3", "name": "1.test.pl", "type": "A", "id": 1} mocked.return_value = [data] - found_dns = self.dnsaas.get_dns_records(['192.168.0.1']) + found_dns = self.dnsaas.get_dns_records(["192.168.0.1"]) self.assertEqual(len(found_dns), 1) - self.assertEqual(found_dns[0]['content'], data['content']) - self.assertEqual(found_dns[0]['name'], data['name']) - self.assertEqual(found_dns[0]['type'], RecordType.a) + self.assertEqual(found_dns[0]["content"], data["content"]) + self.assertEqual(found_dns[0]["name"], data["name"]) + self.assertEqual(found_dns[0]["type"], RecordType.a) - @override_settings(DNSAAS_URL='http://dnsaas.com/') + @override_settings(DNSAAS_URL="http://dnsaas.com/") def test_build_url(self): self.assertEqual( - self.dnsaas.build_url('domains'), - 'http://dnsaas.com/api/domains/' + self.dnsaas.build_url("domains"), "http://dnsaas.com/api/domains/" ) - @override_settings(DNSAAS_URL='http://dnsaas.com/') + @override_settings(DNSAAS_URL="http://dnsaas.com/") def test_build_url_with_version(self): self.assertEqual( - self.dnsaas.build_url('domains'), - 'http://dnsaas.com/api/domains/' + self.dnsaas.build_url("domains"), "http://dnsaas.com/api/domains/" ) - @override_settings(DNSAAS_URL='http://dnsaas.com/') + @override_settings(DNSAAS_URL="http://dnsaas.com/") def test_build_url_with_id(self): self.assertEqual( - self.dnsaas.build_url('domains', id=1), - 'http://dnsaas.com/api/domains/1/' + self.dnsaas.build_url("domains", id=1), "http://dnsaas.com/api/domains/1/" ) - @override_settings(DNSAAS_URL='http://dnsaas.com/') + @override_settings(DNSAAS_URL="http://dnsaas.com/") def test_build_url_with_get_params(self): self.assertEqual( - self.dnsaas.build_url('domains', get_params=[('name', 'ralph')]), - 'http://dnsaas.com/api/domains/?name=ralph' + self.dnsaas.build_url("domains", get_params=[("name", "ralph")]), + "http://dnsaas.com/api/domains/?name=ralph", ) - @override_settings(DNSAAS_URL='http://dnsaas.com/') + @override_settings(DNSAAS_URL="http://dnsaas.com/") def test_build_url_with_id_and_get_params(self): self.assertEqual( - self.dnsaas.build_url( - 'domains', id=1, get_params=[('name', 'ralph')] - ), - 'http://dnsaas.com/api/domains/1/?name=ralph' + self.dnsaas.build_url("domains", id=1, get_params=[("name", "ralph")]), + "http://dnsaas.com/api/domains/1/?name=ralph", ) @@ -99,15 +81,14 @@ def test_dnsaasintegration_disabled(self): DNSView() @override_settings(ENABLE_DNSAAS_INTEGRATION=True) - @patch('ralph.dns.views.DNSaaS._get_oauth_token') + @patch("ralph.dns.views.DNSaaS._get_oauth_token") def test_dnsaasintegration_enabled(self, _get_oauth_token_mock): # should not raise exception - _get_oauth_token_mock.return_value = 'token' + _get_oauth_token_mock.return_value = "token" DNSView() class TestGetTXTDataToPublishToDNSaaS(TestCase): - @classmethod def setUpClass(cls): from ralph.data_center.tests.factories import ( @@ -115,23 +96,24 @@ def setUpClass(cls): DataCenterAssetFactory, RackFactory, ) + super().setUpClass() cls.dc_asset = DataCenterAssetFactory( - hostname='ralph0.allegro.pl', - service_env__service__name='service', - service_env__environment__name='test', - model__name='DL360', - model__manufacturer__name='Asus', - model__category__name='ATS', + hostname="ralph0.allegro.pl", + service_env__service__name="service", + service_env__environment__name="test", + model__name="DL360", + model__manufacturer__name="Asus", + model__category__name="ATS", rack=RackFactory( - name='Rack #100', - server_room__name='Server Room A', - server_room__data_center__name='DC1', + name="Rack #100", + server_room__name="Server Room A", + server_room__data_center__name="DC1", ), position=1, - slot_no='1', - configuration_path__class_name='www', - configuration_path__module__name='ralph', + slot_no="1", + configuration_path__class_name="www", + configuration_path__module__name="ralph", ) cls.dc_ip = IPAddressFactory( base_object=cls.dc_asset, @@ -143,26 +125,25 @@ def setUpClass(cls): is_management=True, ) cls.virtual_server = VirtualServerFactory( - hostname='s000.local', + hostname="s000.local", configuration_path=ConfigurationClassFactory( - class_name='worker', - module__name='auth' + class_name="worker", module__name="auth" ), - service_env__service__name='service', - service_env__environment__name='prod', - type__name='Xen', + service_env__service__name="service", + service_env__environment__name="prod", + type__name="Xen", parent=DataCenterAssetFactory( - hostname='parent', - model__name='DL380p', - model__manufacturer__name='Brother', - model__category__name='Database Machine', + hostname="parent", + model__name="DL380p", + model__manufacturer__name="Brother", + model__category__name="Database Machine", rack=RackFactory( - name='Rack #101', - server_room__name='Server Room B', - server_room__data_center__name='DC2', + name="Rack #101", + server_room__name="Server Room B", + server_room__data_center__name="DC2", ), position=1, - slot_no='1', + slot_no="1", ), ) # refresh virtual server to get parent as BaseObject, not @@ -171,35 +152,34 @@ def setUpClass(cls): base_object=cls.virtual_server, ethernet=EthernetFactory(base_object=cls.virtual_server), ) - cls.virtual_server = VirtualServer.objects.get( - pk=cls.virtual_server.id - ) + cls.virtual_server = VirtualServer.objects.get(pk=cls.virtual_server.id) cluster = ClusterFactory( - hostname='', - type__name='Application', - configuration_path__class_name='www', - configuration_path__module__name='ralph', - service_env__service__name='service', - service_env__environment__name='preprod', + hostname="", + type__name="Application", + configuration_path__class_name="www", + configuration_path__module__name="ralph", + service_env__service__name="service", + service_env__environment__name="preprod", ) cls.boc_1 = BaseObjectCluster.objects.create( cluster=cluster, base_object=DataCenterAssetFactory( - rack=RackFactory(), position=1, - ) + rack=RackFactory(), + position=1, + ), ) cls.boc_2 = BaseObjectCluster.objects.create( cluster=cluster, base_object=DataCenterAssetFactory( rack=RackFactory( - server_room__data_center__name='DC2', - server_room__name='Server Room B', - name='Rack #101', + server_room__data_center__name="DC2", + server_room__name="Server Room B", + name="Rack #101", ), position=1, ), - is_master=True + is_master=True, ) cls.cluster = ClusterFactory._meta.model.objects.get(pk=cluster) @@ -210,276 +190,333 @@ def setUpClass(cls): def test_dc_asset_gets_data_ok(self): data = _get_txt_data_to_publish_to_dnsaas(self.dc_asset) - self.assertEqual(data, [{ - 'content': 'www', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'VENTURE', - 'service_uid': self.dc_asset.service.uid - }, { - 'content': 'ralph', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'ROLE', - 'service_uid': self.dc_asset.service.uid - }, { - 'content': 'ralph/www', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'CONFIGURATION_PATH', - 'service_uid': self.dc_asset.service.uid - }, { - 'content': 'service - test', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'SERVICE_ENV', - 'service_uid': self.dc_asset.service.uid - }, { - 'content': '[ATS] Asus DL360', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'MODEL', - 'service_uid': self.dc_asset.service.uid - }, { - 'content': 'DC1 / Server Room A / Rack #100 / 1 / 1', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'LOCATION', - 'service_uid': self.dc_asset.service.uid - }]) + self.assertEqual( + data, + [ + { + "content": "www", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "VENTURE", + "service_uid": self.dc_asset.service.uid, + }, + { + "content": "ralph", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "ROLE", + "service_uid": self.dc_asset.service.uid, + }, + { + "content": "ralph/www", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "CONFIGURATION_PATH", + "service_uid": self.dc_asset.service.uid, + }, + { + "content": "service - test", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "SERVICE_ENV", + "service_uid": self.dc_asset.service.uid, + }, + { + "content": "[ATS] Asus DL360", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "MODEL", + "service_uid": self.dc_asset.service.uid, + }, + { + "content": "DC1 / Server Room A / Rack #100 / 1 / 1", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "LOCATION", + "service_uid": self.dc_asset.service.uid, + }, + ], + ) def test_dc_asset_without_service_gets_data_ok(self): self.dc_asset.service_env = None self.dc_asset.save() data = _get_txt_data_to_publish_to_dnsaas(self.dc_asset) - self.assertEqual(data, [{ - 'content': 'www', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'VENTURE' - }, { - 'content': 'ralph', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'ROLE' - }, { - 'content': 'ralph/www', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'CONFIGURATION_PATH' - }, { - 'content': '[ATS] Asus DL360', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'MODEL' - }, { - 'content': 'DC1 / Server Room A / Rack #100 / 1 / 1', - 'ips': [self.dc_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'LOCATION' - }]) + self.assertEqual( + data, + [ + { + "content": "www", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "VENTURE", + }, + { + "content": "ralph", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "ROLE", + }, + { + "content": "ralph/www", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "CONFIGURATION_PATH", + }, + { + "content": "[ATS] Asus DL360", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "MODEL", + }, + { + "content": "DC1 / Server Room A / Rack #100 / 1 / 1", + "ips": [self.dc_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "LOCATION", + }, + ], + ) def test_virtual_server_gets_data_ok(self): data = _get_txt_data_to_publish_to_dnsaas(self.virtual_server) - self.assertEqual(data, [{ - 'content': 'worker', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'VENTURE', - 'service_uid': self.virtual_server.service.uid - }, { - 'content': 'auth', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'ROLE', - 'service_uid': self.virtual_server.service.uid - }, { - 'content': 'auth/worker', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'CONFIGURATION_PATH', - 'service_uid': self.virtual_server.service.uid - }, { - 'content': 'service - prod', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'SERVICE_ENV', - 'service_uid': self.virtual_server.service.uid - }, { - 'content': 'Xen', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'MODEL', - 'service_uid': self.virtual_server.service.uid - }, { - 'content': 'DC2 / Server Room B / Rack #101 / 1 / 1 / parent', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'LOCATION', - 'service_uid': self.virtual_server.service.uid - }]) + self.assertEqual( + data, + [ + { + "content": "worker", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "VENTURE", + "service_uid": self.virtual_server.service.uid, + }, + { + "content": "auth", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "ROLE", + "service_uid": self.virtual_server.service.uid, + }, + { + "content": "auth/worker", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "CONFIGURATION_PATH", + "service_uid": self.virtual_server.service.uid, + }, + { + "content": "service - prod", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "SERVICE_ENV", + "service_uid": self.virtual_server.service.uid, + }, + { + "content": "Xen", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "MODEL", + "service_uid": self.virtual_server.service.uid, + }, + { + "content": "DC2 / Server Room B / Rack #101 / 1 / 1 / parent", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "LOCATION", + "service_uid": self.virtual_server.service.uid, + }, + ], + ) def test_virtual_server_without_service_gets_data_ok(self): self.virtual_server.service_env = None self.virtual_server.save() data = _get_txt_data_to_publish_to_dnsaas(self.virtual_server) - self.assertEqual(data, [{ - 'content': 'worker', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'VENTURE' - }, { - 'content': 'auth', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'ROLE' - }, { - 'content': 'auth/worker', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'CONFIGURATION_PATH' - }, { - 'content': 'Xen', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'MODEL' - }, { - 'content': 'DC2 / Server Room B / Rack #101 / 1 / 1 / parent', - 'ips': [self.vs_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'LOCATION' - }]) + self.assertEqual( + data, + [ + { + "content": "worker", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "VENTURE", + }, + { + "content": "auth", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "ROLE", + }, + { + "content": "auth/worker", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "CONFIGURATION_PATH", + }, + { + "content": "Xen", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "MODEL", + }, + { + "content": "DC2 / Server Room B / Rack #101 / 1 / 1 / parent", + "ips": [self.vs_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "LOCATION", + }, + ], + ) def test_cluster_gets_data_ok(self): data = _get_txt_data_to_publish_to_dnsaas(self.cluster) - self.assertEqual(data, [{ - 'content': 'www', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'VENTURE', - 'service_uid': self.cluster.service.uid - }, { - 'content': 'ralph', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'ROLE', - 'service_uid': self.cluster.service.uid - }, { - 'content': 'ralph/www', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'CONFIGURATION_PATH', - 'service_uid': self.cluster.service.uid - }, { - 'content': 'service - preprod', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'SERVICE_ENV', - 'service_uid': self.cluster.service.uid - }, { - 'content': 'Application', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'MODEL', - 'service_uid': self.cluster.service.uid - }, { - 'content': 'DC2 / Server Room B / Rack #101 / 1', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'LOCATION', - 'service_uid': self.cluster.service.uid - }]) + self.assertEqual( + data, + [ + { + "content": "www", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "VENTURE", + "service_uid": self.cluster.service.uid, + }, + { + "content": "ralph", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "ROLE", + "service_uid": self.cluster.service.uid, + }, + { + "content": "ralph/www", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "CONFIGURATION_PATH", + "service_uid": self.cluster.service.uid, + }, + { + "content": "service - preprod", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "SERVICE_ENV", + "service_uid": self.cluster.service.uid, + }, + { + "content": "Application", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "MODEL", + "service_uid": self.cluster.service.uid, + }, + { + "content": "DC2 / Server Room B / Rack #101 / 1", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "LOCATION", + "service_uid": self.cluster.service.uid, + }, + ], + ) def test_cluster_without_service_gets_data_ok(self): self.cluster.service_env = None self.cluster.save() data = _get_txt_data_to_publish_to_dnsaas(self.cluster) - self.assertEqual(data, [{ - 'content': 'www', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'VENTURE' - }, { - 'content': 'ralph', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'ROLE' - }, { - 'content': 'ralph/www', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'CONFIGURATION_PATH' - }, { - 'content': 'Application', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'MODEL' - }, { - 'content': 'DC2 / Server Room B / Rack #101 / 1', - 'ips': [self.cluster_ip.address], - 'owner': 'ralph', - 'target_owner': 'ralph', - 'purpose': 'LOCATION' - }]) + self.assertEqual( + data, + [ + { + "content": "www", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "VENTURE", + }, + { + "content": "ralph", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "ROLE", + }, + { + "content": "ralph/www", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "CONFIGURATION_PATH", + }, + { + "content": "Application", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "MODEL", + }, + { + "content": "DC2 / Server Room B / Rack #101 / 1", + "ips": [self.cluster_ip.address], + "owner": "ralph", + "target_owner": "ralph", + "purpose": "LOCATION", + }, + ], + ) class TestPublishAutoTXTToDNSaaS(TransactionTestCase): - @classmethod def setUpClass(cls): from ralph.data_center.tests.factories import ( DataCenterAssetFactory, RackFactory, ) + super().setUpClass() cls.dc_asset = DataCenterAssetFactory( - hostname='ralph0.allegro.pl', - service_env__service__name='service', - service_env__environment__name='test', - model__name='DL360', - model__manufacturer__name='Asus', - model__category__name='ATS', + hostname="ralph0.allegro.pl", + service_env__service__name="service", + service_env__environment__name="test", + model__name="DL360", + model__manufacturer__name="Asus", + model__category__name="ATS", rack=RackFactory( - name='Rack #100', - server_room__name='Server Room A', - server_room__data_center__name='DC1', + name="Rack #100", + server_room__name="Server Room A", + server_room__data_center__name="DC1", ), position=1, - slot_no='1', - configuration_path__class_name='www', - configuration_path__module__name='ralph', + slot_no="1", + configuration_path__class_name="www", + configuration_path__module__name="ralph", ) cls.dc_ip = IPAddressFactory( base_object=cls.dc_asset, @@ -491,10 +528,8 @@ def setUpClass(cls): is_management=True, ) - @override_settings( - DNSAAS_AUTO_TXT_RECORD_TOPIC_NAME='dnsaas_auto_txt_record' - ) - @patch('ralph.dns.publishers.publish') + @override_settings(DNSAAS_AUTO_TXT_RECORD_TOPIC_NAME="dnsaas_auto_txt_record") + @patch("ralph.dns.publishers.publish") def test_publishing_auto_txt_data_when_dc_asset_updated(self, publish_mock): # fetch clean instance dc_asset = DataCenterAsset.objects.get(pk=self.dc_asset) @@ -506,51 +541,59 @@ def test_publishing_auto_txt_data_when_dc_asset_updated(self, publish_mock): # owner could be non-deterministic, depending on order of tests # and it's not part of this test to check its correctness for data_dict in publish_data: - data_dict.pop('owner') - self.assertCountEqual(publish_data, [ - { - 'content': 'www', - 'ips': [self.dc_ip.address], - 'target_owner': 'ralph', - 'purpose': 'VENTURE', - 'service_uid': dc_asset.service.uid - }, { - 'content': 'ralph', - 'ips': [self.dc_ip.address], - 'target_owner': 'ralph', - 'purpose': 'ROLE', - 'service_uid': dc_asset.service.uid - }, { - 'content': 'ralph/www', - 'ips': [self.dc_ip.address], - 'target_owner': 'ralph', - 'purpose': 'CONFIGURATION_PATH', - 'service_uid': dc_asset.service.uid - }, { - 'content': 'service - test', - 'ips': [self.dc_ip.address], - 'target_owner': 'ralph', - 'purpose': 'SERVICE_ENV', - 'service_uid': dc_asset.service.uid - }, { - 'content': '[ATS] Asus DL360', - 'ips': [self.dc_ip.address], - 'target_owner': 'ralph', - 'purpose': 'MODEL', - 'service_uid': dc_asset.service.uid - }, { - 'content': 'DC1 / Server Room A / Rack #100 / 1 / 1', - 'ips': [self.dc_ip.address], - 'target_owner': 'ralph', - 'purpose': 'LOCATION', - 'service_uid': dc_asset.service.uid - } - ]) + data_dict.pop("owner") + self.assertCountEqual( + publish_data, + [ + { + "content": "www", + "ips": [self.dc_ip.address], + "target_owner": "ralph", + "purpose": "VENTURE", + "service_uid": dc_asset.service.uid, + }, + { + "content": "ralph", + "ips": [self.dc_ip.address], + "target_owner": "ralph", + "purpose": "ROLE", + "service_uid": dc_asset.service.uid, + }, + { + "content": "ralph/www", + "ips": [self.dc_ip.address], + "target_owner": "ralph", + "purpose": "CONFIGURATION_PATH", + "service_uid": dc_asset.service.uid, + }, + { + "content": "service - test", + "ips": [self.dc_ip.address], + "target_owner": "ralph", + "purpose": "SERVICE_ENV", + "service_uid": dc_asset.service.uid, + }, + { + "content": "[ATS] Asus DL360", + "ips": [self.dc_ip.address], + "target_owner": "ralph", + "purpose": "MODEL", + "service_uid": dc_asset.service.uid, + }, + { + "content": "DC1 / Server Room A / Rack #100 / 1 / 1", + "ips": [self.dc_ip.address], + "target_owner": "ralph", + "purpose": "LOCATION", + "service_uid": dc_asset.service.uid, + }, + ], + ) class TestDNSForm(TestCase): def test_unknown_field_goes_to_non_field_errors(self): - errors = {'errors': [{'reason': 'unknown', 'comment': 'value'}]} + errors = {"errors": [{"reason": "unknown", "comment": "value"}]} form = DNSRecordForm({}) add_errors(form, errors) - self.assertIn('value', form.non_field_errors()) + self.assertIn("value", form.non_field_errors()) diff --git a/src/ralph/dns/views.py b/src/ralph/dns/views.py index 545df4e012..77a42f732e 100644 --- a/src/ralph/dns/views.py +++ b/src/ralph/dns/views.py @@ -19,9 +19,9 @@ class DNSaaSIntegrationNotEnabledError(Exception): class DnsaasErrorReasonToFieldNameEnum(Enum): - NAME = 'name' - TYPE = 'type' - CONTENT = 'content' + NAME = "name" + TYPE = "type" + CONTENT = "content" _DEFAULT = None @@ -32,23 +32,23 @@ def add_errors(form, errors): form: Django form, form.Form errors: list of errors from DNSAAS """ - for error in errors.get('errors', []): - reason = error.get('reason', '_DEFAULT') + for error in errors.get("errors", []): + reason = error.get("reason", "_DEFAULT") try: field_name = DnsaasErrorReasonToFieldNameEnum[reason].value except KeyError: field_name = DnsaasErrorReasonToFieldNameEnum._DEFAULT.value - field_error = error.get('comment', 'Unknown error') + field_error = error.get("comment", "Unknown error") form.add_error(field_name, field_error) class DNSView(RalphDetailView): - icon = 'chain-broken' - name = 'dns_edit' - label = 'DNS' - url_name = 'dns_edit' - template_name = 'dns/dns_edit.html' + icon = "chain-broken" + name = "dns_edit" + label = "DNS" + url_name = "dns_edit" + template_name = "dns/dns_edit.html" def __init__(self, *args, **kwargs): if not settings.ENABLE_DNSAAS_INTEGRATION: @@ -58,9 +58,7 @@ def __init__(self, *args, **kwargs): def get_forms(self): forms = [] - ipaddresses = self.object.ipaddresses.all().values_list( - 'address', flat=True - ) + ipaddresses = self.object.ipaddresses.all().values_list("address", flat=True) if not ipaddresses: # If ipaddresses is empty return empty form list because we can not # identify the records do not have any IP address @@ -70,9 +68,9 @@ def get_forms(self): for item in initial: forms.append(DNSRecordForm(item)) - if initial and initial[0]['type'] == RecordType.a.id: + if initial and initial[0]["type"] == RecordType.a.id: # from API "A" record is always first - empty_form = DNSRecordForm(initial={'name': initial[0]['name']}) + empty_form = DNSRecordForm(initial={"name": initial[0]["name"]}) else: empty_form = DNSRecordForm() @@ -80,8 +78,8 @@ def get_forms(self): return forms def get(self, request, *args, **kwargs): - if 'forms' not in kwargs: - kwargs['forms'] = self.get_forms() + if "forms" not in kwargs: + kwargs["forms"] = self.get_forms() return super().get(request, *kwargs, **kwargs) def post(self, request, *args, **kwargs): @@ -89,41 +87,30 @@ def post(self, request, *args, **kwargs): posted_form = DNSRecordForm(request.POST) # Find form which request's data belongs to for i, form in enumerate(forms): - if ( - str(form.data.get('pk', '')) == - str(posted_form.data.get('pk', '')) - ): + if str(form.data.get("pk", "")) == str(posted_form.data.get("pk", "")): forms[i] = posted_form break if posted_form.is_valid(): - if posted_form.data.get('delete'): - errors = self.dnsaas.delete_dns_record(form.data['pk']) + if posted_form.data.get("delete"): + errors = self.dnsaas.delete_dns_record(form.data["pk"]) if not errors: - messages.success( - request, _('DNS record has been deleted.') - ) - elif posted_form.cleaned_data.get('pk'): - errors = self.dnsaas.update_dns_record( - posted_form.cleaned_data - ) + messages.success(request, _("DNS record has been deleted.")) + elif posted_form.cleaned_data.get("pk"): + errors = self.dnsaas.update_dns_record(posted_form.cleaned_data) if not errors: - messages.success( - request, _('DNS record has been updated.') - ) + messages.success(request, _("DNS record has been updated.")) else: errors = self.dnsaas.create_dns_record( posted_form.cleaned_data, service=self.object.service ) if not errors: - messages.success( - request, _('DNS record has been created.') - ) + messages.success(request, _("DNS record has been created.")) if errors: add_errors(posted_form, errors) else: - return HttpResponseRedirect('.') + return HttpResponseRedirect(".") - kwargs['forms'] = forms + kwargs["forms"] = forms return self.get(request, *args, **kwargs) diff --git a/src/ralph/domains/__init__.py b/src/ralph/domains/__init__.py index 5d9062f4e0..6bf62e4655 100644 --- a/src/ralph/domains/__init__.py +++ b/src/ralph/domains/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.domains.apps.Domains' +default_app_config = "ralph.domains.apps.Domains" diff --git a/src/ralph/domains/admin.py b/src/ralph/domains/admin.py index d710b91cd2..bd6d41ab0e 100644 --- a/src/ralph/domains/admin.py +++ b/src/ralph/domains/admin.py @@ -14,7 +14,7 @@ DomainCategory, DomainContract, DomainProviderAdditionalServices, - DomainRegistrant + DomainRegistrant, ) @@ -28,40 +28,72 @@ class DomainAdmin(AttachmentsMixin, RalphAdmin): form = DomainForm resource_class = DomainResource list_select_related = [ - 'technical_owner', 'business_owner', 'domain_holder', + "technical_owner", + "business_owner", + "domain_holder", ] list_filter = [ - 'name', 'service_env', 'domain_status', 'business_segment', - 'domain_holder', ('domaincontract__expiration_date', DateListFilter), - 'website_type', 'website_url', - 'dns_provider', 'domain_category', 'domain_type', - 'additional_services' + "name", + "service_env", + "domain_status", + "business_segment", + "domain_holder", + ("domaincontract__expiration_date", DateListFilter), + "website_type", + "website_url", + "dns_provider", + "domain_category", + "domain_type", + "additional_services", ] list_display = [ - 'name', 'business_owner', - 'technical_owner', 'domain_holder', 'service_env', 'expiration_date' + "name", + "business_owner", + "technical_owner", + "domain_holder", + "service_env", + "expiration_date", ] raw_id_fields = [ - 'service_env', 'business_owner', 'technical_owner', 'domain_holder' + "service_env", + "business_owner", + "technical_owner", + "domain_holder", ] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', 'remarks', 'domain_status', 'website_type', - 'website_url', 'domain_category', 'domain_type', - 'dns_provider', 'additional_services' - ) - }), - (_('Ownership info'), { - 'fields': ( - 'service_env', - 'business_segment', 'business_owner', - 'technical_owner', 'domain_holder' - ) - }) + ( + _("Basic info"), + { + "fields": ( + "name", + "remarks", + "domain_status", + "website_type", + "website_url", + "domain_category", + "domain_type", + "dns_provider", + "additional_services", + ) + }, + ), + ( + _("Ownership info"), + { + "fields": ( + "service_env", + "business_segment", + "business_owner", + "technical_owner", + "domain_holder", + ) + }, + ), ) - search_fields = ['name', ] - inlines = (DomainContractInline, ) + search_fields = [ + "name", + ] + inlines = (DomainContractInline,) def expiration_date(self, obj): links = [] @@ -69,38 +101,28 @@ def expiration_date(self, obj): link = '{} ({})'.format( contract.get_absolute_url(), contract.expiration_date, - contract.registrant or '-', - + contract.registrant or "-", ) links.append(link) - return format_html('
    '.join(links)) - expiration_date.short_description = 'Expiration date' + return format_html("
    ".join(links)) + + expiration_date.short_description = "Expiration date" @register(DomainContract) class DomainContractAdmin(AttachmentsMixin, RalphAdmin): form = DomainContractForm resource_class = DomainContractResource - list_select_related = ['domain', 'domain__service_env'] - list_filter = [ - 'domain__name', 'domain__service_env__service__name' - ] - list_display = [ - 'domain', 'expiration_date', 'price' - ] + list_select_related = ["domain", "domain__service_env"] + list_filter = ["domain__name", "domain__service_env__service__name"] + list_display = ["domain", "expiration_date", "price"] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'domain', 'expiration_date', 'registrant' - ) - }), - (_('Financial info'), { - 'fields': ( - 'price', - ) - }), + (_("Basic info"), {"fields": ("domain", "expiration_date", "registrant")}), + (_("Financial info"), {"fields": ("price",)}), ) - search_fields = ['domain__name', ] + search_fields = [ + "domain__name", + ] @register(DomainProviderAdditionalServices) diff --git a/src/ralph/domains/api.py b/src/ralph/domains/api.py index dc1f110c01..037bfb935f 100644 --- a/src/ralph/domains/api.py +++ b/src/ralph/domains/api.py @@ -7,7 +7,6 @@ class DomainProviderAdditionalServicesSerializer(RalphAPISerializer): - class Meta: model = DomainProviderAdditionalServices fields = "__all__" @@ -32,12 +31,19 @@ class DomainViewSet(RalphAPIViewSet): queryset = Domain.objects.all() serializer_class = DomainSerializer select_related = [ - 'service_env__service', 'service_env__environment', 'business_segment', - 'business_owner', 'technical_owner', 'domain_holder' + "service_env__service", + "service_env__environment", + "business_segment", + "business_owner", + "technical_owner", + "domain_holder", ] prefetch_related = [ - 'tags', 'custom_fields', 'content_type', - 'additional_services', 'licences__baseobjectlicence_set' + "tags", + "custom_fields", + "content_type", + "additional_services", + "licences__baseobjectlicence_set", ] @@ -63,11 +69,10 @@ class DomainCategoryViewSet(RalphAPIViewSet): serializer_class = DomainCategorySerializer -router.register(r'domains', DomainViewSet) +router.register(r"domains", DomainViewSet) router.register( - r'domain-provider-additional-services', - DomainProviderAdditionalServicesViewSet + r"domain-provider-additional-services", DomainProviderAdditionalServicesViewSet ) -router.register(r'dns-provider', DNSProviderViewSet) -router.register(r'domain-category', DomainCategoryViewSet) +router.register(r"dns-provider", DNSProviderViewSet) +router.register(r"domain-category", DomainCategoryViewSet) urlpatterns = [] diff --git a/src/ralph/domains/apps.py b/src/ralph/domains/apps.py index 745485e296..8812c65c38 100644 --- a/src/ralph/domains/apps.py +++ b/src/ralph/domains/apps.py @@ -3,10 +3,9 @@ class Domains(RalphAppConfig): - - name = 'ralph.domains' + name = "ralph.domains" def get_load_modules_when_ready(self): if settings.ENABLE_HERMES_INTEGRATION: - return ['publishers'] + return ["publishers"] return [] diff --git a/src/ralph/domains/forms.py b/src/ralph/domains/forms.py index 81b9dd4dca..7dace474ec 100644 --- a/src/ralph/domains/forms.py +++ b/src/ralph/domains/forms.py @@ -11,13 +11,11 @@ class Meta: model = Domain exclude = [] widgets = { - 'additional_services': CheckboxSelectMultiple, + "additional_services": CheckboxSelectMultiple, } class DomainContractForm(PriceFormMixin, RalphAdminForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['price'].help_text = _( - "Price for domain renewal for given period" - ) + self.fields["price"].help_text = _("Price for domain renewal for given period") diff --git a/src/ralph/domains/migrations/0001_initial.py b/src/ralph/domains/migrations/0001_initial.py index 6e0da2da13..cafc61505a 100644 --- a/src/ralph/domains/migrations/0001_initial.py +++ b/src/ralph/domains/migrations/0001_initial.py @@ -8,59 +8,181 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0001_initial'), + ("assets", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='Domain', + name="Domain", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(verbose_name='Domain name', help_text='Full domain name', unique=True, max_length=255)), - ('domain_status', models.PositiveIntegerField(choices=[(1, 'Active'), (2, 'Pending lapse'), (3, 'Pending transfer away'), (4, 'Lapsed (inactive)'), (5, 'Transfered away')], default=1)), - ('business_owner', models.ForeignKey(to=settings.AUTH_USER_MODEL, blank=True, null=True, help_text='Business contact person for a domain', related_name='domaincontract_business_owner', on_delete=django.db.models.deletion.CASCADE)), - ('business_segment', models.ForeignKey(to='assets.BusinessSegment', blank=True, null=True, help_text='Business segment for a domain', on_delete=django.db.models.deletion.CASCADE)), - ('domain_holder', models.ForeignKey(to='assets.AssetHolder', blank=True, null=True, help_text='Company which receives invoice for the domain', on_delete=django.db.models.deletion.CASCADE)), - ('technical_owner', models.ForeignKey(to=settings.AUTH_USER_MODEL, blank=True, null=True, help_text='Technical contact person for a domain', related_name='domaincontract_technical_owner', on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "name", + models.CharField( + verbose_name="Domain name", + help_text="Full domain name", + unique=True, + max_length=255, + ), + ), + ( + "domain_status", + models.PositiveIntegerField( + choices=[ + (1, "Active"), + (2, "Pending lapse"), + (3, "Pending transfer away"), + (4, "Lapsed (inactive)"), + (5, "Transfered away"), + ], + default=1, + ), + ), + ( + "business_owner", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, + blank=True, + null=True, + help_text="Business contact person for a domain", + related_name="domaincontract_business_owner", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "business_segment", + models.ForeignKey( + to="assets.BusinessSegment", + blank=True, + null=True, + help_text="Business segment for a domain", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "domain_holder", + models.ForeignKey( + to="assets.AssetHolder", + blank=True, + null=True, + help_text="Company which receives invoice for the domain", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "technical_owner", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, + blank=True, + null=True, + help_text="Technical contact person for a domain", + related_name="domaincontract_technical_owner", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('assets.baseobject', ralph.lib.mixins.models.AdminAbsoluteUrlMixin), + bases=("assets.baseobject", ralph.lib.mixins.models.AdminAbsoluteUrlMixin), ), migrations.CreateModel( - name='DomainContract', + name="DomainContract", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('expiration_date', models.DateField(blank=True, null=True)), - ('price', models.DecimalField(decimal_places=2, verbose_name='Price', blank=True, null=True, help_text='Price for domain renewal for given period', max_digits=15)), - ('domain', models.ForeignKey(to='domains.Domain', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ("expiration_date", models.DateField(blank=True, null=True)), + ( + "price", + models.DecimalField( + decimal_places=2, + verbose_name="Price", + blank=True, + null=True, + help_text="Price for domain renewal for given period", + max_digits=15, + ), + ), + ( + "domain", + models.ForeignKey( + to="domains.Domain", on_delete=django.db.models.deletion.CASCADE + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='DomainRegistrant', + name="DomainRegistrant", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.AddField( - model_name='domaincontract', - name='registrant', - field=models.ForeignKey(to='domains.DomainRegistrant', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="domaincontract", + name="registrant", + field=models.ForeignKey( + to="domains.DomainRegistrant", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/domains/migrations/0002_auto_20151125_1354.py b/src/ralph/domains/migrations/0002_auto_20151125_1354.py index 6b7a362df7..9ea5721e3e 100644 --- a/src/ralph/domains/migrations/0002_auto_20151125_1354.py +++ b/src/ralph/domains/migrations/0002_auto_20151125_1354.py @@ -5,30 +5,29 @@ class Migration(migrations.Migration): - dependencies = [ - ('domains', '0001_initial'), + ("domains", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='domaincontract', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="domaincontract", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='domaincontract', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="domaincontract", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='domainregistrant', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="domainregistrant", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='domainregistrant', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="domainregistrant", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), ] diff --git a/src/ralph/domains/migrations/0003_auto_20160823_0921.py b/src/ralph/domains/migrations/0003_auto_20160823_0921.py index 4b3c2a97d0..2bedc724cf 100644 --- a/src/ralph/domains/migrations/0003_auto_20160823_0921.py +++ b/src/ralph/domains/migrations/0003_auto_20160823_0921.py @@ -5,15 +5,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('domains', '0002_auto_20151125_1354'), + ("domains", "0002_auto_20151125_1354"), ] operations = [ migrations.AlterField( - model_name='domain', - name='name', - field=models.CharField(unique=True, help_text='Full domain name', max_length=255, verbose_name='domain name'), + model_name="domain", + name="name", + field=models.CharField( + unique=True, + help_text="Full domain name", + max_length=255, + verbose_name="domain name", + ), ), ] diff --git a/src/ralph/domains/migrations/0004_auto_20160907_1100.py b/src/ralph/domains/migrations/0004_auto_20160907_1100.py index bf9e0af44e..cb299ac73e 100644 --- a/src/ralph/domains/migrations/0004_auto_20160907_1100.py +++ b/src/ralph/domains/migrations/0004_auto_20160907_1100.py @@ -5,20 +5,28 @@ class Migration(migrations.Migration): - dependencies = [ - ('domains', '0003_auto_20160823_0921'), + ("domains", "0003_auto_20160823_0921"), ] operations = [ migrations.AddField( - model_name='domain', - name='website_type', - field=models.PositiveIntegerField(default=3, help_text='Type of website which domain refers to.', choices=[(1, 'None'), (2, 'Redirect'), (3, 'Direct')]), + model_name="domain", + name="website_type", + field=models.PositiveIntegerField( + default=3, + help_text="Type of website which domain refers to.", + choices=[(1, "None"), (2, "Redirect"), (3, "Direct")], + ), ), migrations.AddField( - model_name='domain', - name='website_url', - field=models.URLField(help_text='Website url which website type refers to.', max_length=255, blank=True, null=True), + model_name="domain", + name="website_url", + field=models.URLField( + help_text="Website url which website type refers to.", + max_length=255, + blank=True, + null=True, + ), ), ] diff --git a/src/ralph/domains/migrations/0005_auto_20170523_1214.py b/src/ralph/domains/migrations/0005_auto_20170523_1214.py index 85990ddd8b..4512c2226e 100644 --- a/src/ralph/domains/migrations/0005_auto_20170523_1214.py +++ b/src/ralph/domains/migrations/0005_auto_20170523_1214.py @@ -7,51 +7,102 @@ class Migration(migrations.Migration): - dependencies = [ - ('domains', '0004_auto_20160907_1100'), + ("domains", "0004_auto_20160907_1100"), ] operations = [ migrations.CreateModel( - name='DNSProvider', + name="DNSProvider", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)), - ('name', models.CharField(max_length=255, unique=True, verbose_name='name')), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + auto_created=True, + serialize=False, + ), + ), + ( + "name", + models.CharField(max_length=255, unique=True, verbose_name="name"), + ), + ( + "created", + models.DateTimeField( + auto_now_add=True, verbose_name="date created" + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), ], options={ - 'abstract': False, + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='DomainCategory', + name="DomainCategory", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)), - ('name', models.CharField(max_length=255, unique=True, verbose_name='name')), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + auto_created=True, + serialize=False, + ), + ), + ( + "name", + models.CharField(max_length=255, unique=True, verbose_name="name"), + ), + ( + "created", + models.DateTimeField( + auto_now_add=True, verbose_name="date created" + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), ], options={ - 'abstract': False, + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.AddField( - model_name='domain', - name='domain_type', - field=models.PositiveIntegerField(choices=[(1, 'Business'), (2, 'Business security'), (3, 'Technical')], default=1), + model_name="domain", + name="domain_type", + field=models.PositiveIntegerField( + choices=[(1, "Business"), (2, "Business security"), (3, "Technical")], + default=1, + ), ), migrations.AddField( - model_name='domain', - name='dns_provider', - field=models.ForeignKey(to='domains.DNSProvider', null=True, help_text="Provider which keeps domain's DNS", blank=True, on_delete=django.db.models.deletion.CASCADE), + model_name="domain", + name="dns_provider", + field=models.ForeignKey( + to="domains.DNSProvider", + null=True, + help_text="Provider which keeps domain's DNS", + blank=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='domain', - name='domain_category', - field=models.ForeignKey(to='domains.DomainCategory', null=True, blank=True, on_delete=django.db.models.deletion.CASCADE), + model_name="domain", + name="domain_category", + field=models.ForeignKey( + to="domains.DomainCategory", + null=True, + blank=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/domains/migrations/0006_auto_20180725_1216.py b/src/ralph/domains/migrations/0006_auto_20180725_1216.py index f81d7f2033..9a61bd8bc4 100644 --- a/src/ralph/domains/migrations/0006_auto_20180725_1216.py +++ b/src/ralph/domains/migrations/0006_auto_20180725_1216.py @@ -6,29 +6,49 @@ class Migration(migrations.Migration): - dependencies = [ - ('domains', '0005_auto_20170523_1214'), + ("domains", "0005_auto_20170523_1214"), ] operations = [ migrations.CreateModel( - name='DomainProviderAdditionalServices', + name="DomainProviderAdditionalServices", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('name', models.CharField(unique=True, verbose_name='name', max_length=255)), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(unique=True, verbose_name="name", max_length=255), + ), + ( + "created", + models.DateTimeField( + auto_now_add=True, verbose_name="date created" + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.AddField( - model_name='domain', - name='additional_services', - field=models.ManyToManyField(blank=True, to='domains.DomainProviderAdditionalServices'), + model_name="domain", + name="additional_services", + field=models.ManyToManyField( + blank=True, to="domains.DomainProviderAdditionalServices" + ), ), ] diff --git a/src/ralph/domains/migrations/0007_auto_20200909_1012.py b/src/ralph/domains/migrations/0007_auto_20200909_1012.py index e8f64118f2..53ad4ac141 100644 --- a/src/ralph/domains/migrations/0007_auto_20200909_1012.py +++ b/src/ralph/domains/migrations/0007_auto_20200909_1012.py @@ -1,26 +1,227 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import djmoney.models.fields from decimal import Decimal class Migration(migrations.Migration): - dependencies = [ - ('domains', '0006_auto_20180725_1216'), + ("domains", "0006_auto_20180725_1216"), ] operations = [ migrations.AddField( - model_name='domaincontract', - name='price_currency', - field=djmoney.models.fields.CurrencyField(max_length=3, default='XXX', editable=False, choices=[('XXX', '---'), ('AED', 'AED'), ('AFN', 'AFN'), ('ALL', 'ALL'), ('AMD', 'AMD'), ('ANG', 'ANG'), ('AOA', 'AOA'), ('ARS', 'ARS'), ('AUD', 'AUD'), ('AWG', 'AWG'), ('AZN', 'AZN'), ('BAM', 'BAM'), ('BBD', 'BBD'), ('BDT', 'BDT'), ('BGN', 'BGN'), ('BHD', 'BHD'), ('BIF', 'BIF'), ('BMD', 'BMD'), ('BND', 'BND'), ('BOB', 'BOB'), ('BOV', 'BOV'), ('BRL', 'BRL'), ('BSD', 'BSD'), ('BTN', 'BTN'), ('BWP', 'BWP'), ('BYN', 'BYN'), ('BYR', 'BYR'), ('BZD', 'BZD'), ('CAD', 'CAD'), ('CDF', 'CDF'), ('CHE', 'CHE'), ('CHF', 'CHF'), ('CHW', 'CHW'), ('CLF', 'CLF'), ('CLP', 'CLP'), ('CNY', 'CNY'), ('COP', 'COP'), ('COU', 'COU'), ('CRC', 'CRC'), ('CUC', 'CUC'), ('CUP', 'CUP'), ('CVE', 'CVE'), ('CZK', 'CZK'), ('DJF', 'DJF'), ('DKK', 'DKK'), ('DOP', 'DOP'), ('DZD', 'DZD'), ('EGP', 'EGP'), ('ERN', 'ERN'), ('ETB', 'ETB'), ('EUR', 'EUR'), ('FJD', 'FJD'), ('FKP', 'FKP'), ('GBP', 'GBP'), ('GEL', 'GEL'), ('GHS', 'GHS'), ('GIP', 'GIP'), ('GMD', 'GMD'), ('GNF', 'GNF'), ('GTQ', 'GTQ'), ('GYD', 'GYD'), ('HKD', 'HKD'), ('HNL', 'HNL'), ('HRK', 'HRK'), ('HTG', 'HTG'), ('HUF', 'HUF'), ('IDR', 'IDR'), ('ILS', 'ILS'), ('IMP', 'IMP'), ('INR', 'INR'), ('IQD', 'IQD'), ('IRR', 'IRR'), ('ISK', 'ISK'), ('JMD', 'JMD'), ('JOD', 'JOD'), ('JPY', 'JPY'), ('KES', 'KES'), ('KGS', 'KGS'), ('KHR', 'KHR'), ('KMF', 'KMF'), ('KPW', 'KPW'), ('KRW', 'KRW'), ('KWD', 'KWD'), ('KYD', 'KYD'), ('KZT', 'KZT'), ('LAK', 'LAK'), ('LBP', 'LBP'), ('LKR', 'LKR'), ('LRD', 'LRD'), ('LSL', 'LSL'), ('LTL', 'LTL'), ('LVL', 'LVL'), ('LYD', 'LYD'), ('MAD', 'MAD'), ('MDL', 'MDL'), ('MGA', 'MGA'), ('MKD', 'MKD'), ('MMK', 'MMK'), ('MNT', 'MNT'), ('MOP', 'MOP'), ('MRO', 'MRO'), ('MUR', 'MUR'), ('MVR', 'MVR'), ('MWK', 'MWK'), ('MXN', 'MXN'), ('MXV', 'MXV'), ('MYR', 'MYR'), ('MZN', 'MZN'), ('NAD', 'NAD'), ('NGN', 'NGN'), ('NIO', 'NIO'), ('NOK', 'NOK'), ('NPR', 'NPR'), ('NZD', 'NZD'), ('OMR', 'OMR'), ('PAB', 'PAB'), ('PEN', 'PEN'), ('PGK', 'PGK'), ('PHP', 'PHP'), ('PKR', 'PKR'), ('PLN', 'PLN'), ('PYG', 'PYG'), ('QAR', 'QAR'), ('RON', 'RON'), ('RSD', 'RSD'), ('RUB', 'RUB'), ('RWF', 'RWF'), ('SAR', 'SAR'), ('SBD', 'SBD'), ('SCR', 'SCR'), ('SDG', 'SDG'), ('SEK', 'SEK'), ('SGD', 'SGD'), ('SHP', 'SHP'), ('SLL', 'SLL'), ('SOS', 'SOS'), ('SRD', 'SRD'), ('SSP', 'SSP'), ('STD', 'STD'), ('SVC', 'SVC'), ('SYP', 'SYP'), ('SZL', 'SZL'), ('THB', 'THB'), ('TJS', 'TJS'), ('TMM', 'TMM'), ('TMT', 'TMT'), ('TND', 'TND'), ('TOP', 'TOP'), ('TRY', 'TRY'), ('TTD', 'TTD'), ('TVD', 'TVD'), ('TWD', 'TWD'), ('TZS', 'TZS'), ('UAH', 'UAH'), ('UGX', 'UGX'), ('USD', 'USD'), ('USN', 'USN'), ('UYI', 'UYI'), ('UYU', 'UYU'), ('UZS', 'UZS'), ('VEF', 'VEF'), ('VND', 'VND'), ('VUV', 'VUV'), ('WST', 'WST'), ('XAF', 'XAF'), ('XAG', 'XAG'), ('XAU', 'XAU'), ('XBA', 'XBA'), ('XBB', 'XBB'), ('XBC', 'XBC'), ('XBD', 'XBD'), ('XCD', 'XCD'), ('XDR', 'XDR'), ('XFO', 'XFO'), ('XFU', 'XFU'), ('XOF', 'XOF'), ('XPD', 'XPD'), ('XPF', 'XPF'), ('XPT', 'XPT'), ('XSU', 'XSU'), ('XTS', 'XTS'), ('XUA', 'XUA'), ('XYZ', 'XYZ'), ('YER', 'YER'), ('ZAR', 'ZAR'), ('ZMK', 'ZMK'), ('ZMW', 'ZMW'), ('ZWD', 'ZWD'), ('ZWL', 'ZWL'), ('ZWN', 'ZWN')]), + model_name="domaincontract", + name="price_currency", + field=djmoney.models.fields.CurrencyField( + max_length=3, + default="XXX", + editable=False, + choices=[ + ("XXX", "---"), + ("AED", "AED"), + ("AFN", "AFN"), + ("ALL", "ALL"), + ("AMD", "AMD"), + ("ANG", "ANG"), + ("AOA", "AOA"), + ("ARS", "ARS"), + ("AUD", "AUD"), + ("AWG", "AWG"), + ("AZN", "AZN"), + ("BAM", "BAM"), + ("BBD", "BBD"), + ("BDT", "BDT"), + ("BGN", "BGN"), + ("BHD", "BHD"), + ("BIF", "BIF"), + ("BMD", "BMD"), + ("BND", "BND"), + ("BOB", "BOB"), + ("BOV", "BOV"), + ("BRL", "BRL"), + ("BSD", "BSD"), + ("BTN", "BTN"), + ("BWP", "BWP"), + ("BYN", "BYN"), + ("BYR", "BYR"), + ("BZD", "BZD"), + ("CAD", "CAD"), + ("CDF", "CDF"), + ("CHE", "CHE"), + ("CHF", "CHF"), + ("CHW", "CHW"), + ("CLF", "CLF"), + ("CLP", "CLP"), + ("CNY", "CNY"), + ("COP", "COP"), + ("COU", "COU"), + ("CRC", "CRC"), + ("CUC", "CUC"), + ("CUP", "CUP"), + ("CVE", "CVE"), + ("CZK", "CZK"), + ("DJF", "DJF"), + ("DKK", "DKK"), + ("DOP", "DOP"), + ("DZD", "DZD"), + ("EGP", "EGP"), + ("ERN", "ERN"), + ("ETB", "ETB"), + ("EUR", "EUR"), + ("FJD", "FJD"), + ("FKP", "FKP"), + ("GBP", "GBP"), + ("GEL", "GEL"), + ("GHS", "GHS"), + ("GIP", "GIP"), + ("GMD", "GMD"), + ("GNF", "GNF"), + ("GTQ", "GTQ"), + ("GYD", "GYD"), + ("HKD", "HKD"), + ("HNL", "HNL"), + ("HRK", "HRK"), + ("HTG", "HTG"), + ("HUF", "HUF"), + ("IDR", "IDR"), + ("ILS", "ILS"), + ("IMP", "IMP"), + ("INR", "INR"), + ("IQD", "IQD"), + ("IRR", "IRR"), + ("ISK", "ISK"), + ("JMD", "JMD"), + ("JOD", "JOD"), + ("JPY", "JPY"), + ("KES", "KES"), + ("KGS", "KGS"), + ("KHR", "KHR"), + ("KMF", "KMF"), + ("KPW", "KPW"), + ("KRW", "KRW"), + ("KWD", "KWD"), + ("KYD", "KYD"), + ("KZT", "KZT"), + ("LAK", "LAK"), + ("LBP", "LBP"), + ("LKR", "LKR"), + ("LRD", "LRD"), + ("LSL", "LSL"), + ("LTL", "LTL"), + ("LVL", "LVL"), + ("LYD", "LYD"), + ("MAD", "MAD"), + ("MDL", "MDL"), + ("MGA", "MGA"), + ("MKD", "MKD"), + ("MMK", "MMK"), + ("MNT", "MNT"), + ("MOP", "MOP"), + ("MRO", "MRO"), + ("MUR", "MUR"), + ("MVR", "MVR"), + ("MWK", "MWK"), + ("MXN", "MXN"), + ("MXV", "MXV"), + ("MYR", "MYR"), + ("MZN", "MZN"), + ("NAD", "NAD"), + ("NGN", "NGN"), + ("NIO", "NIO"), + ("NOK", "NOK"), + ("NPR", "NPR"), + ("NZD", "NZD"), + ("OMR", "OMR"), + ("PAB", "PAB"), + ("PEN", "PEN"), + ("PGK", "PGK"), + ("PHP", "PHP"), + ("PKR", "PKR"), + ("PLN", "PLN"), + ("PYG", "PYG"), + ("QAR", "QAR"), + ("RON", "RON"), + ("RSD", "RSD"), + ("RUB", "RUB"), + ("RWF", "RWF"), + ("SAR", "SAR"), + ("SBD", "SBD"), + ("SCR", "SCR"), + ("SDG", "SDG"), + ("SEK", "SEK"), + ("SGD", "SGD"), + ("SHP", "SHP"), + ("SLL", "SLL"), + ("SOS", "SOS"), + ("SRD", "SRD"), + ("SSP", "SSP"), + ("STD", "STD"), + ("SVC", "SVC"), + ("SYP", "SYP"), + ("SZL", "SZL"), + ("THB", "THB"), + ("TJS", "TJS"), + ("TMM", "TMM"), + ("TMT", "TMT"), + ("TND", "TND"), + ("TOP", "TOP"), + ("TRY", "TRY"), + ("TTD", "TTD"), + ("TVD", "TVD"), + ("TWD", "TWD"), + ("TZS", "TZS"), + ("UAH", "UAH"), + ("UGX", "UGX"), + ("USD", "USD"), + ("USN", "USN"), + ("UYI", "UYI"), + ("UYU", "UYU"), + ("UZS", "UZS"), + ("VEF", "VEF"), + ("VND", "VND"), + ("VUV", "VUV"), + ("WST", "WST"), + ("XAF", "XAF"), + ("XAG", "XAG"), + ("XAU", "XAU"), + ("XBA", "XBA"), + ("XBB", "XBB"), + ("XBC", "XBC"), + ("XBD", "XBD"), + ("XCD", "XCD"), + ("XDR", "XDR"), + ("XFO", "XFO"), + ("XFU", "XFU"), + ("XOF", "XOF"), + ("XPD", "XPD"), + ("XPF", "XPF"), + ("XPT", "XPT"), + ("XSU", "XSU"), + ("XTS", "XTS"), + ("XUA", "XUA"), + ("XYZ", "XYZ"), + ("YER", "YER"), + ("ZAR", "ZAR"), + ("ZMK", "ZMK"), + ("ZMW", "ZMW"), + ("ZWD", "ZWD"), + ("ZWL", "ZWL"), + ("ZWN", "ZWN"), + ], + ), ), migrations.AlterField( - model_name='domaincontract', - name='price', - field=djmoney.models.fields.MoneyField(null=True, default=Decimal('0'), max_digits=15, decimal_places=2, default_currency='XXX'), + model_name="domaincontract", + name="price", + field=djmoney.models.fields.MoneyField( + null=True, + default=Decimal("0"), + max_digits=15, + decimal_places=2, + default_currency="XXX", + ), ), ] diff --git a/src/ralph/domains/migrations/0008_auto_20240621_1011.py b/src/ralph/domains/migrations/0008_auto_20240621_1011.py index 2b20c55d97..e5b85ef7ac 100644 --- a/src/ralph/domains/migrations/0008_auto_20240621_1011.py +++ b/src/ralph/domains/migrations/0008_auto_20240621_1011.py @@ -7,16 +7,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('domains', '0007_auto_20200909_1012'), + ("domains", "0007_auto_20200909_1012"), ] operations = [ migrations.AlterModelManagers( - name='domain', + name="domain", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/domains/models/__init__.py b/src/ralph/domains/models/__init__.py index c58a7a2300..82a9b82cc2 100644 --- a/src/ralph/domains/models/__init__.py +++ b/src/ralph/domains/models/__init__.py @@ -8,10 +8,10 @@ ) __all__ = [ - 'Domain', - 'DomainCategory', - 'DomainContract', - 'DomainRegistrant', - 'DomainStatus', - 'DNSProvider', + "Domain", + "DomainCategory", + "DomainContract", + "DomainRegistrant", + "DomainStatus", + "DNSProvider", ] diff --git a/src/ralph/domains/models/domains.py b/src/ralph/domains/models/domains.py index 1749d45e68..4ffdf2f18c 100644 --- a/src/ralph/domains/models/domains.py +++ b/src/ralph/domains/models/domains.py @@ -12,7 +12,7 @@ AdminAbsoluteUrlMixin, NamedMixin, PriceMixin, - TimeStampMixin + TimeStampMixin, ) from ralph.lib.permissions.models import PermByFieldMixin @@ -30,27 +30,27 @@ class DomainRegistrant( class DomainStatus(Choices): _ = Choices.Choice - active = _('Active') - pending_lapse = _('Pending lapse') - pending_transfer = _('Pending transfer away') - lapsed = _('Lapsed (inactive)') - transfered_away = _('Transfered away') + active = _("Active") + pending_lapse = _("Pending lapse") + pending_transfer = _("Pending transfer away") + lapsed = _("Lapsed (inactive)") + transfered_away = _("Transfered away") class WebsiteType(Choices): _ = Choices.Choice - none = _('None') - redirect = _('Redirect') - direct = _('Direct') + none = _("None") + redirect = _("Redirect") + direct = _("Direct") class DomainType(Choices): _ = Choices.Choice - business = _('Business') - business_security = _('Business security') - technical = _('Technical') + business = _("Business") + business_security = _("Business security") + technical = _("Technical") class DomainCategory( @@ -74,52 +74,51 @@ class DNSProvider( class DomainProviderAdditionalServices( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model + AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model ): pass class Domain(BaseObject, AdminAbsoluteUrlMixin, models.Model): name = models.CharField( - verbose_name=_('domain name'), - help_text=_('Full domain name'), + verbose_name=_("domain name"), + help_text=_("Full domain name"), unique=True, - max_length=255 + max_length=255, ) domain_status = models.PositiveIntegerField( choices=DomainStatus(), default=DomainStatus.active.id, ) business_segment = models.ForeignKey( - BusinessSegment, blank=True, null=True, + BusinessSegment, + blank=True, + null=True, help_text=_("Business segment for a domain"), - on_delete=models.CASCADE + on_delete=models.CASCADE, ) business_owner = models.ForeignKey( settings.AUTH_USER_MODEL, - related_name='domaincontract_business_owner', + related_name="domaincontract_business_owner", blank=True, null=True, help_text=_("Business contact person for a domain"), - on_delete=models.CASCADE + on_delete=models.CASCADE, ) technical_owner = models.ForeignKey( settings.AUTH_USER_MODEL, - related_name='domaincontract_technical_owner', + related_name="domaincontract_technical_owner", blank=True, null=True, help_text=_("Technical contact person for a domain"), - on_delete=models.CASCADE + on_delete=models.CASCADE, ) domain_holder = models.ForeignKey( AssetHolder, blank=True, null=True, help_text=_("Company which receives invoice for the domain"), - on_delete=models.CASCADE + on_delete=models.CASCADE, ) domain_type = models.PositiveIntegerField( default=DomainType.business.id, @@ -128,19 +127,23 @@ class Domain(BaseObject, AdminAbsoluteUrlMixin, models.Model): website_type = models.PositiveIntegerField( default=WebsiteType.direct.id, choices=WebsiteType(), - help_text=_("Type of website which domain refers to.") + help_text=_("Type of website which domain refers to."), ) website_url = models.URLField( - max_length=255, blank=True, null=True, - help_text=_("Website url which website type refers to.") + max_length=255, + blank=True, + null=True, + help_text=_("Website url which website type refers to."), ) domain_category = models.ForeignKey( DomainCategory, blank=True, null=True, on_delete=models.CASCADE ) dns_provider = models.ForeignKey( - DNSProvider, blank=True, null=True, + DNSProvider, + blank=True, + null=True, help_text=_("Provider which keeps domain's DNS"), - on_delete=models.CASCADE + on_delete=models.CASCADE, ) additional_services = models.ManyToManyField( DomainProviderAdditionalServices, @@ -152,24 +155,14 @@ def __str__(self): def clean(self): super().clean() - if ( - self.website_type == WebsiteType.none.id and - self.website_url - ): - raise ValidationError({ - 'website_url': _( - 'Website url should be empty for this website type' - ) - }) - elif ( - self.website_type == WebsiteType.redirect.id and - not self.website_url - ): - raise ValidationError({ - 'website_url': _( - 'Website url should be filled for this website type' - ) - }) + if self.website_type == WebsiteType.none.id and self.website_url: + raise ValidationError( + {"website_url": _("Website url should be empty for this website type")} + ) + elif self.website_type == WebsiteType.redirect.id and not self.website_url: + raise ValidationError( + {"website_url": _("Website url should be filled for this website type")} + ) class DomainContract( @@ -182,14 +175,10 @@ class DomainContract( domain = models.ForeignKey(Domain, on_delete=models.CASCADE) expiration_date = models.DateField(null=True, blank=True) registrant = models.ForeignKey( - 'DomainRegistrant', - null=True, - blank=True, - on_delete=models.CASCADE + "DomainRegistrant", null=True, blank=True, on_delete=models.CASCADE ) def __str__(self): return "{domain_name} - {expiration_date}".format( - domain_name=self.domain.name, - expiration_date=self.expiration_date + domain_name=self.domain.name, expiration_date=self.expiration_date ) diff --git a/src/ralph/domains/publishers.py b/src/ralph/domains/publishers.py index 2e3d251900..f3ff5e65e6 100644 --- a/src/ralph/domains/publishers.py +++ b/src/ralph/domains/publishers.py @@ -15,31 +15,34 @@ def _publish_domain_data(domain): owners = [] if domain.business_owner: - owners.append({ - 'username': domain.business_owner.username, - 'ownership_type': settings.DOMAIN_OWNER_TYPE['BO'], - }) + owners.append( + { + "username": domain.business_owner.username, + "ownership_type": settings.DOMAIN_OWNER_TYPE["BO"], + } + ) if domain.technical_owner: - owners.append({ - 'username': domain.technical_owner.username, - 'ownership_type': settings.DOMAIN_OWNER_TYPE['TO'], - }) + owners.append( + { + "username": domain.technical_owner.username, + "ownership_type": settings.DOMAIN_OWNER_TYPE["TO"], + } + ) domain_data = { - 'domain_name': domain.name, - 'service_uid': domain.service.uid if domain.service else '', - 'owners': owners, + "domain_name": domain.name, + "service_uid": domain.service.uid if domain.service else "", + "owners": owners, } logger.info(domain_data) return domain_data if settings.DOMAIN_DATA_UPDATE_TOPIC: - logger.info('registered: {}'.format(settings.DOMAIN_DATA_UPDATE_TOPIC)) + logger.info("registered: {}".format(settings.DOMAIN_DATA_UPDATE_TOPIC)) @pyhermes.publisher( - topic=settings.DOMAIN_DATA_UPDATE_TOPIC, - auto_publish_result=True + topic=settings.DOMAIN_DATA_UPDATE_TOPIC, auto_publish_result=True ) def publish_domain_data(obj): return _publish_domain_data(obj) diff --git a/src/ralph/domains/tests/factories.py b/src/ralph/domains/tests/factories.py index de204711b9..8ef0008251 100644 --- a/src/ralph/domains/tests/factories.py +++ b/src/ralph/domains/tests/factories.py @@ -10,14 +10,13 @@ DomainCategory, DomainContract, DomainRegistrant, - DomainStatus + DomainStatus, ) from ralph.domains.models.domains import DomainProviderAdditionalServices class DomainFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'www.domain{}.com'.format(n)) + name = factory.Sequence(lambda n: "www.domain{}.com".format(n)) domain_status = DomainStatus.active technical_owner = factory.SubFactory(UserFactory) business_owner = factory.SubFactory(UserFactory) @@ -28,21 +27,20 @@ class Meta: class DNSProviderFactory(DjangoModelFactory): - name = factory.Sequence(lambda n: 'dns-provider{}'.format(n)) + name = factory.Sequence(lambda n: "dns-provider{}".format(n)) class Meta: model = DNSProvider class DomainCategoryFactory(DjangoModelFactory): - name = factory.Sequence(lambda n: 'domain-contract{}'.format(n)) + name = factory.Sequence(lambda n: "domain-contract{}".format(n)) class Meta: model = DomainCategory class DomainContractFactory(DjangoModelFactory): - domain = factory.SubFactory(DomainFactory) class Meta: @@ -50,16 +48,16 @@ class Meta: class DomainRegistrantFactory(DjangoModelFactory): - - name = factory.Iterator(['ovh', 'home.pl', 'nazwa.pl']) + name = factory.Iterator(["ovh", "home.pl", "nazwa.pl"]) class Meta: model = DomainRegistrant - django_get_or_create = ['name'] + django_get_or_create = ["name"] + class DomainProviderAdditionalServicesFactory(DjangoModelFactory): - name = factory.Iterator(['Masking', 'Backorder', 'Acquisition']) + name = factory.Iterator(["Masking", "Backorder", "Acquisition"]) class Meta: model = DomainProviderAdditionalServices - django_get_or_create = ['name'] + django_get_or_create = ["name"] diff --git a/src/ralph/domains/tests/tests.py b/src/ralph/domains/tests/tests.py index 34a0237cba..f0a0c3b475 100644 --- a/src/ralph/domains/tests/tests.py +++ b/src/ralph/domains/tests/tests.py @@ -11,39 +11,45 @@ class TestDomainValidation(TestCase): def test_pass_when_type_redirect_and_value(self): domain = DomainFactory( - website_type=WebsiteType.redirect.id, website_url='www.allegro.pl', + website_type=WebsiteType.redirect.id, + website_url="www.allegro.pl", ) domain.clean() def test_raise_error_when_type_redirect_and_no_value(self): domain = DomainFactory( - website_type=WebsiteType.redirect.id, website_url='', + website_type=WebsiteType.redirect.id, + website_url="", ) with self.assertRaises(ValidationError): domain.clean() def test_pass_when_type_none_and_no_value(self): domain = DomainFactory( - website_type=WebsiteType.none.id, website_url='', + website_type=WebsiteType.none.id, + website_url="", ) domain.clean() def test_raise_error_when_type_none_and_value(self): domain = DomainFactory( - website_type=WebsiteType.none.id, website_url='www.allegro.pl', + website_type=WebsiteType.none.id, + website_url="www.allegro.pl", ) with self.assertRaises(ValidationError): domain.clean() def test_pass_when_type_direct_and_value(self): domain = DomainFactory( - website_type=WebsiteType.direct.id, website_url='www.allegro.pl', + website_type=WebsiteType.direct.id, + website_url="www.allegro.pl", ) domain.clean() def test_pass_when_type_direct_and_no_value(self): domain = DomainFactory( - website_type=WebsiteType.direct.id, website_url='', + website_type=WebsiteType.direct.id, + website_url="", ) domain.clean() @@ -54,7 +60,7 @@ def test_domain_update_returns_domain_name(self): result = _publish_domain_data(domain) - self.assertEqual(domain.name, result['domain_name']) + self.assertEqual(domain.name, result["domain_name"]) def test_domain_update_returns_business_owners(self): domain = DomainFactory(technical_owner=None) @@ -62,11 +68,13 @@ def test_domain_update_returns_business_owners(self): result = _publish_domain_data(domain) self.assertEqual( - [{ - 'username': domain.business_owner.username, - 'ownership_type': settings.DOMAIN_OWNER_TYPE['BO'], - }], - result['owners'] + [ + { + "username": domain.business_owner.username, + "ownership_type": settings.DOMAIN_OWNER_TYPE["BO"], + } + ], + result["owners"], ) def test_domain_update_returns_technical_owners(self): @@ -75,11 +83,13 @@ def test_domain_update_returns_technical_owners(self): result = _publish_domain_data(domain) self.assertEqual( - [{ - 'username': domain.technical_owner.username, - 'ownership_type': settings.DOMAIN_OWNER_TYPE['TO'], - }], - result['owners'] + [ + { + "username": domain.technical_owner.username, + "ownership_type": settings.DOMAIN_OWNER_TYPE["TO"], + } + ], + result["owners"], ) def test_domain_update_returns_empty_owners_when_no_owners(self): @@ -87,16 +97,14 @@ def test_domain_update_returns_empty_owners_when_no_owners(self): result = _publish_domain_data(domain) - self.assertEqual(result['owners'], []) + self.assertEqual(result["owners"], []) def test_domain_update_returns_service_uid(self): domain = DomainFactory() result = _publish_domain_data(domain) - self.assertEqual( - domain.service.uid, result['service_uid'] - ) + self.assertEqual(domain.service.uid, result["service_uid"]) def test_domain_update_returns_empty_when_no_service(self): domain = DomainFactory() @@ -105,4 +113,4 @@ def test_domain_update_returns_empty_when_no_service(self): result = _publish_domain_data(domain) - self.assertEqual(result['service_uid'], '') + self.assertEqual(result["service_uid"], "") diff --git a/src/ralph/health_check.py b/src/ralph/health_check.py index c90c3f8f3d..1e7c30be82 100644 --- a/src/ralph/health_check.py +++ b/src/ralph/health_check.py @@ -19,7 +19,7 @@ def _test_redis_conn(): def _test_db_conn(): - connections['default'].cursor() + connections["default"].cursor() def _perform_all_health_checks(): @@ -28,30 +28,24 @@ def _perform_all_health_checks(): try: health_check_func() except Exception as e: - msg = 'Health check failed. Function: {}, exception: {}'.format( + msg = "Health check failed. Function: {}, exception: {}".format( health_check_func.__name__, e ) - logger.critical( - msg, - extra={ - 'action_type': 'HEALTH_CHECK', - 'error': str(e) - } - ) + logger.critical(msg, extra={"action_type": "HEALTH_CHECK", "error": str(e)}) messages.append(msg) return messages @require_GET def status_ping(request): - return HttpResponse('pong', content_type='text/plain') + return HttpResponse("pong", content_type="text/plain") @require_GET def status_health(request): health_checks_errors = _perform_all_health_checks() if not health_checks_errors: - return HttpResponse('Healthy', content_type='text/plain') + return HttpResponse("Healthy", content_type="text/plain") else: - response = 'Not Healthy\n' + "\n".join(health_checks_errors) - return HttpResponse(response, status=503, content_type='text/plain') + response = "Not Healthy\n" + "\n".join(health_checks_errors) + return HttpResponse(response, status=503, content_type="text/plain") diff --git a/src/ralph/helpers.py b/src/ralph/helpers.py index f5572599fd..a26ec0a719 100644 --- a/src/ralph/helpers.py +++ b/src/ralph/helpers.py @@ -21,9 +21,9 @@ def get_model_view_url_name(model, view_name, with_admin_namespace=True): 'admin:data_center_datacenterasset_attachment' """ params = model._meta.app_label, model._meta.model_name - url = '{}_{}_{view_name}'.format(*params, view_name=view_name) + url = "{}_{}_{view_name}".format(*params, view_name=view_name) if with_admin_namespace: - url = 'admin:' + url + url = "admin:" + url return url @@ -34,9 +34,10 @@ def generate_pdf_response(pdf_data, file_name): """ # TODO: unify with attachments response = HttpResponse( - content=pdf_data, content_type='application/pdf', + content=pdf_data, + content_type="application/pdf", ) - response['Content-Disposition'] = 'attachment; filename="{}"'.format( + response["Content-Disposition"] = 'attachment; filename="{}"'.format( file_name, ) return response @@ -59,25 +60,24 @@ def cache(seconds=300, cache_name=DEFAULT_CACHE_ALIAS, skip_first=False): when calculating hash of arguments (useful when first argument is instance of a class (self)). """ + def _cache(func): @wraps(func) def wrapper(*args, **kwargs): cache_proxy = caches[cache_name] - key = _cache_key_hash( - func, *(args[1:] if skip_first else args), **kwargs - ) + key = _cache_key_hash(func, *(args[1:] if skip_first else args), **kwargs) result = cache_proxy.get(key, default=CACHE_DEFAULT) if result is CACHE_DEFAULT: - logger.debug('Recalculating result of {}'.format(func.__name__)) + logger.debug("Recalculating result of {}".format(func.__name__)) result = func(*args, **kwargs) cache_proxy.set(key, result, seconds) else: - logger.debug( - 'Taking result of {} from cache'.format(func.__name__) - ) + logger.debug("Taking result of {} from cache".format(func.__name__)) return result + if settings.USE_CACHE: return wrapper else: return func + return _cache diff --git a/src/ralph/lib/custom_fields/api/routers.py b/src/ralph/lib/custom_fields/api/routers.py index 4a7b6b2047..37e680373c 100644 --- a/src/ralph/lib/custom_fields/api/routers.py +++ b/src/ralph/lib/custom_fields/api/routers.py @@ -14,16 +14,16 @@ class NestedCustomFieldsRouterMixin(object): # URL path used to build nested resource for customfields nested_resource_prefix = r'customfields' # name of nested resource for customfields, used by DRF (ex. to reverse URL) - nested_resource_base_name = '{}-customfields' + nested_resource_basename = '{}-customfields' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.nested_registry = [] - def register(self, prefix, viewset, base_name=None): - super().register(prefix, viewset, base_name=base_name) - if base_name is None: - base_name = self.get_default_base_name(viewset) + def register(self, prefix, viewset, basename=None): + super().register(prefix, viewset, basename=basename) + if basename is None: + basename = self.get_default_basename(viewset) from .serializers import WithCustomFieldsSerializerMixin if ( issubclass( @@ -32,9 +32,9 @@ def register(self, prefix, viewset, base_name=None): getattr(viewset, '_nested_custom_fields', True) ): # additionally, registed nested resource for custom fields - self._attach_nested_custom_fields(prefix, viewset, base_name) + self._attach_nested_custom_fields(prefix, viewset, basename) - def _attach_nested_custom_fields(self, prefix, viewset, base_name): + def _attach_nested_custom_fields(self, prefix, viewset, basename): """ Creates dedicated viewset for nested customfields in context of particular model. @@ -58,13 +58,13 @@ def _attach_nested_custom_fields(self, prefix, viewset, base_name): nested_router.register( self.nested_resource_prefix, custom_fields_related_viewset, - base_name=self.nested_resource_base_name.format(base_name), + basename=self.nested_resource_basename.format(basename), ) self.nested_registry.append(nested_router) def get_urls(self): urls = super().get_urls() - # additionaly, return nested routers urls too + # additionally, return nested routers urls too for nr in self.nested_registry: urls.append(url(r'^', include(nr.urls))) return urls diff --git a/src/ralph/lib/custom_fields/api/serializers.py b/src/ralph/lib/custom_fields/api/serializers.py index b3537b2fdd..bb24f3f95f 100644 --- a/src/ralph/lib/custom_fields/api/serializers.py +++ b/src/ralph/lib/custom_fields/api/serializers.py @@ -28,7 +28,7 @@ class CustomFieldValueSerializerMixin(object): # default field class to use for url field custom_field_value_url_field = CustomFieldValueHyperlinkedIdentityField # nested resource name used by `NestedCustomFieldsRouterMixin` - custom_fields_nested_resource_base_name = 'customfields' + custom_fields_nested_resource_basename = 'customfields' class Meta: model = CustomFieldValue @@ -57,7 +57,7 @@ def _get_custom_field_value_url_kwargs(self, model_class): return { 'view_name': '{}-{}-detail'.format( self.related_model._meta.model_name, - self.custom_fields_nested_resource_base_name + self.custom_fields_nested_resource_basename ), } diff --git a/src/ralph/lib/transitions/api/routers.py b/src/ralph/lib/transitions/api/routers.py index d9b330a590..9cad70ee13 100644 --- a/src/ralph/lib/transitions/api/routers.py +++ b/src/ralph/lib/transitions/api/routers.py @@ -22,7 +22,7 @@ router.register( r'(?P\w+)/(?P\w+)/(?P\w+)/transitions', AvailableTransitionViewSet, - base_name='available-transiton' + basename='available-transiton' ) urlpatterns = [ diff --git a/src/ralph/licences/admin.py b/src/ralph/licences/admin.py index f8c9873d0e..2d5158413a 100644 --- a/src/ralph/licences/admin.py +++ b/src/ralph/licences/admin.py @@ -3,11 +3,7 @@ from ralph.admin.decorators import register from ralph.admin.filters import TagsListFilter -from ralph.admin.mixins import ( - BulkEditChangeListMixin, - RalphAdmin, - RalphTabularInline -) +from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphTabularInline from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.assets.invoice_report import InvoiceReportMixin from ralph.attachments.admin import AttachmentsMixin @@ -19,36 +15,36 @@ Licence, LicenceType, LicenceUser, - Software + Software, ) class BaseObjectLicenceView(RalphDetailViewAdmin): - icon = 'laptop' - name = 'base-object' - label = _('Assignments') - url_name = 'assignments' + icon = "laptop" + name = "base-object" + label = _("Assignments") + url_name = "assignments" class BaseObjectLicenceInline(RalphTabularInline): model = BaseObjectLicence - raw_id_fields = ('base_object',) + raw_id_fields = ("base_object",) extra = 1 - verbose_name = _('assignments') - verbose_name_plural = _('Assignments') - fk_name = 'licence' + verbose_name = _("assignments") + verbose_name_plural = _("Assignments") + fk_name = "licence" inlines = [BaseObjectLicenceInline] class LicenceUserView(RalphDetailViewAdmin): - icon = 'user' - name = 'users' - label = _('Assigned to users') - url_name = 'assigned-to-users' + icon = "user" + name = "users" + label = _("Assigned to users") + url_name = "assigned-to-users" class LicenceUserInline(RalphTabularInline): model = LicenceUser - raw_id_fields = ('user',) + raw_id_fields = ("user",) extra = 1 inlines = [LicenceUserInline] @@ -58,11 +54,12 @@ class LicenseAdminForm(PriceFormMixin, RalphAdmin.form): """ Service_env is not required for Licenses. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # backward compatibility - service_env_field = self.fields.get('service_env', None) + service_env_field = self.fields.get("service_env", None) if service_env_field: service_env_field.required = False @@ -73,84 +70,157 @@ class LicenceAdmin( AttachmentsMixin, BulkEditChangeListMixin, InvoiceReportMixin, - RalphAdmin + RalphAdmin, ): - """Licence admin class.""" - actions = ['bulk_edit_action'] + + actions = ["bulk_edit_action"] form = LicenseAdminForm change_views = [ BaseObjectLicenceView, LicenceUserView, ] - search_fields = [ - 'software__name', 'niw', 'sn', 'license_details', 'remarks' - ] + search_fields = ["software__name", "niw", "sn", "license_details", "remarks"] list_filter = [ - 'niw', 'sn', 'remarks', 'software', 'property_of', - 'licence_type', 'service_env', 'valid_thru', 'order_no', 'invoice_no', - 'invoice_date', 'budget_info', 'manufacturer', - 'manufacturer__manufacturer_kind', 'region', - 'office_infrastructure', TagsListFilter + "niw", + "sn", + "remarks", + "software", + "property_of", + "licence_type", + "service_env", + "valid_thru", + "order_no", + "invoice_no", + "invoice_date", + "budget_info", + "manufacturer", + "manufacturer__manufacturer_kind", + "region", + "office_infrastructure", + TagsListFilter, ] - date_hierarchy = 'created' + date_hierarchy = "created" list_display = [ - 'niw', 'licence_type', 'software', 'manufacturer', 'service_env', - 'invoice_date', 'invoice_no', 'valid_thru', 'created', 'region', - 'property_of', 'number_bought', 'used', 'free' + "niw", + "licence_type", + "software", + "manufacturer", + "service_env", + "invoice_date", + "invoice_no", + "valid_thru", + "created", + "region", + "property_of", + "number_bought", + "used", + "free", ] - readonly_fields = ['used', 'free'] + readonly_fields = ["used", "free"] list_select_related = [ - 'licence_type', 'software', 'region', 'property_of', 'manufacturer', - 'service_env', 'service_env__service', 'service_env__environment' + "licence_type", + "software", + "region", + "property_of", + "manufacturer", + "service_env", + "service_env__service", + "service_env__environment", ] raw_id_fields = [ - 'software', 'manufacturer', 'budget_info', 'office_infrastructure', - 'service_env', + "software", + "manufacturer", + "budget_info", + "office_infrastructure", + "service_env", ] bulk_edit_list = [ - 'manufacturer', 'licence_type', 'property_of', 'software', - 'number_bought', 'invoice_no', 'invoice_date', 'valid_thru', - 'order_no', 'price', 'accounting_id', 'provider', 'service_env', 'niw', - 'sn', 'remarks', 'budget_info', 'region', 'start_usage' + "manufacturer", + "licence_type", + "property_of", + "software", + "number_bought", + "invoice_no", + "invoice_date", + "valid_thru", + "order_no", + "price", + "accounting_id", + "provider", + "service_env", + "niw", + "sn", + "remarks", + "budget_info", + "region", + "start_usage", ] resource_class = resources.LicenceResource - _invoice_report_name = 'invoice-licence' - _invoice_report_select_related = ['software', 'manufacturer'] + _invoice_report_name = "invoice-licence" + _invoice_report_select_related = ["software", "manufacturer"] _invoice_report_empty_value = None _invoice_report_item_fields = [ - 'software', 'manufacturer', 'software__get_asset_type_display', 'niw', - 'sn', 'price', 'created', 'number_bought', 'start_usage' + "software", + "manufacturer", + "software__get_asset_type_display", + "niw", + "sn", + "price", + "created", + "number_bought", + "start_usage", ] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'licence_type', 'manufacturer', 'software', 'niw', 'sn', - 'valid_thru', 'license_details', 'region', 'remarks', - 'service_env' - ) - }), - (_('Financial info'), { - 'fields': ( - 'order_no', 'invoice_no', 'price', 'depreciation_rate', - 'invoice_date', 'number_bought', 'used', 'free', - 'accounting_id', 'start_usage', 'budget_info', 'provider', - 'office_infrastructure', 'property_of' - ) - }), + ( + _("Basic info"), + { + "fields": ( + "licence_type", + "manufacturer", + "software", + "niw", + "sn", + "valid_thru", + "license_details", + "region", + "remarks", + "service_env", + ) + }, + ), + ( + _("Financial info"), + { + "fields": ( + "order_no", + "invoice_no", + "price", + "depreciation_rate", + "invoice_date", + "number_bought", + "used", + "free", + "accounting_id", + "start_usage", + "budget_info", + "provider", + "office_infrastructure", + "property_of", + ) + }, + ), ) - _queryset_manager = 'objects_used_free' - _export_queryset_manager = 'objects_used_free_with_related' + _queryset_manager = "objects_used_free" + _export_queryset_manager = "objects_used_free_with_related" @register(LicenceType) class LicenceTypeAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(Software) class Software(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] diff --git a/src/ralph/licences/api.py b/src/ralph/licences/api.py index bdb0383765..78cbdf2fb3 100644 --- a/src/ralph/licences/api.py +++ b/src/ralph/licences/api.py @@ -5,7 +5,7 @@ from ralph.api.serializers import ReversionHistoryAPISerializerMixin from ralph.assets.api.serializers import ( BaseObjectSimpleSerializer, - ServiceEnvironmentSimpleSerializer + ServiceEnvironmentSimpleSerializer, ) from ralph.lib.api.utils import renderer_classes_without_form from ralph.licences.models import ( @@ -13,7 +13,7 @@ Licence, LicenceType, LicenceUser, - Software + Software, ) @@ -35,10 +35,8 @@ class Meta: class BaseObjectLicenceSerializer( - ReversionHistoryAPISerializerMixin, - RalphAPISerializer + ReversionHistoryAPISerializerMixin, RalphAPISerializer ): - class Meta: model = BaseObjectLicence fields = "__all__" @@ -51,17 +49,15 @@ def validate(self, data): class LicenceSerializer(BaseObjectSimpleSerializer): base_objects = BaseObjectLicenceSerializer( - many=True, read_only=True, source='baseobjectlicence_set' - ) - users = LicenceUserSerializer( - many=True, read_only=True, source='licenceuser_set' + many=True, read_only=True, source="baseobjectlicence_set" ) + users = LicenceUserSerializer(many=True, read_only=True, source="licenceuser_set") service_env = ServiceEnvironmentSimpleSerializer() class Meta: model = Licence depth = 1 - exclude = ('content_type', 'configuration_path') + exclude = ("content_type", "configuration_path") class SoftwareSerializer(RalphAPISerializer): @@ -78,12 +74,15 @@ class BaseObjectLicenceViewSet(RalphAPIViewSet): queryset = BaseObjectLicence.objects.all() serializer_class = BaseObjectLicenceSerializer select_related = [ - 'licence', - 'base_object', - 'licence__region', 'licence__manufacturer', - 'licence__licence_type', 'licence__software', - 'licence__budget_info', 'licence__office_infrastructure', - 'licence__property_of', + "licence", + "base_object", + "licence__region", + "licence__manufacturer", + "licence__licence_type", + "licence__software", + "licence__budget_info", + "licence__office_infrastructure", + "licence__property_of", ] save_serializer_class = BaseObjectLicenceSerializer @@ -98,13 +97,24 @@ class LicenceViewSet(RalphAPIViewSet): queryset = Licence.objects.all() serializer_class = LicenceSerializer select_related = [ - 'region', 'manufacturer', 'office_infrastructure', 'licence_type', - 'software', 'service_env', 'service_env__service', - 'service_env__environment', 'budget_info', 'property_of', + "region", + "manufacturer", + "office_infrastructure", + "licence_type", + "software", + "service_env", + "service_env__service", + "service_env__environment", + "budget_info", + "property_of", ] prefetch_related = [ - 'tags', 'users', 'licenceuser_set__user', - 'baseobjectlicence_set__base_object', 'custom_fields', 'content_type' + "tags", + "users", + "licenceuser_set__user", + "baseobjectlicence_set__base_object", + "custom_fields", + "content_type", ] @@ -112,9 +122,13 @@ class LicenceUserViewSet(RalphAPIViewSet): queryset = LicenceUser.objects.all() serializer_class = LicenceUserSerializer select_related = [ - 'licence__region', 'licence__manufacturer', 'licence__office_infrastructure', - 'licence__licence_type', 'licence__software', 'licence__budget_info', - 'user' + "licence__region", + "licence__manufacturer", + "licence__office_infrastructure", + "licence__licence_type", + "licence__software", + "licence__budget_info", + "user", ] @@ -123,9 +137,9 @@ class SoftwareViewSet(RalphAPIViewSet): serializer_class = SoftwareSerializer -router.register(r'base-objects-licences', BaseObjectLicenceViewSet) -router.register(r'licences', LicenceViewSet) -router.register(r'licence-types', LicenceTypeViewSet) -router.register(r'licence-users', LicenceUserViewSet) -router.register(r'software', SoftwareViewSet) +router.register(r"base-objects-licences", BaseObjectLicenceViewSet) +router.register(r"licences", LicenceViewSet) +router.register(r"licence-types", LicenceTypeViewSet) +router.register(r"licence-users", LicenceUserViewSet) +router.register(r"software", SoftwareViewSet) urlpatterns = [] diff --git a/src/ralph/licences/api_simple.py b/src/ralph/licences/api_simple.py index 795dfd40fb..af4d86bf9f 100644 --- a/src/ralph/licences/api_simple.py +++ b/src/ralph/licences/api_simple.py @@ -11,13 +11,17 @@ class Meta: model = Licence depth = 1 exclude = ( - 'base_objects', 'users', 'content_type', 'service_env', 'parent', - 'configuration_path' + "base_objects", + "users", + "content_type", + "service_env", + "parent", + "configuration_path", ) # FIXME -del SimpleLicenceSerializer._declared_fields['tags'] +del SimpleLicenceSerializer._declared_fields["tags"] class SimpleLicenceUserSerializer(RalphAPISerializer): diff --git a/src/ralph/licences/migrations/0001_initial.py b/src/ralph/licences/migrations/0001_initial.py index feecb87364..526529827c 100644 --- a/src/ralph/licences/migrations/0001_initial.py +++ b/src/ralph/licences/migrations/0001_initial.py @@ -8,126 +8,308 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0001_initial'), + ("assets", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('accounts', '0001_initial'), - ('back_office', '0001_initial'), + ("accounts", "0001_initial"), + ("back_office", "0001_initial"), ] operations = [ migrations.CreateModel( - name='BaseObjectLicence', + name="BaseObjectLicence", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('quantity', models.PositiveIntegerField(default=1)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("quantity", models.PositiveIntegerField(default=1)), ], ), migrations.CreateModel( - name='Licence', + name="Licence", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), - ('number_bought', models.IntegerField(verbose_name='Number of purchased items')), - ('sn', models.TextField(verbose_name='SN / Key', blank=True, null=True)), - ('niw', models.CharField(verbose_name='Inventory number', default='N/A', unique=True, max_length=200)), - ('invoice_date', models.DateField(verbose_name='Invoice date', blank=True, null=True)), - ('valid_thru', models.DateField(blank=True, null=True, help_text='Leave blank if this licence is perpetual')), - ('order_no', models.CharField(blank=True, null=True, max_length=50)), - ('price', models.DecimalField(blank=True, default=0, null=True, decimal_places=2, max_digits=10)), - ('accounting_id', models.CharField(blank=True, null=True, help_text='Any value to help your accounting department identify this licence', max_length=200)), - ('provider', models.CharField(blank=True, null=True, max_length=100)), - ('invoice_no', models.CharField(blank=True, db_index=True, null=True, max_length=128)), - ('license_details', models.CharField(verbose_name='License details', blank=True, default='', max_length=1024)), - ('base_objects', models.ManyToManyField(verbose_name='Assigned base objects', through='licences.BaseObjectLicence', to='assets.BaseObject', related_name='_licence_base_objects_+')), - ('budget_info', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, default=None, to='assets.BudgetInfo', blank=True, null=True)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "number_bought", + models.IntegerField(verbose_name="Number of purchased items"), + ), + ( + "sn", + models.TextField(verbose_name="SN / Key", blank=True, null=True), + ), + ( + "niw", + models.CharField( + verbose_name="Inventory number", + default="N/A", + unique=True, + max_length=200, + ), + ), + ( + "invoice_date", + models.DateField( + verbose_name="Invoice date", blank=True, null=True + ), + ), + ( + "valid_thru", + models.DateField( + blank=True, + null=True, + help_text="Leave blank if this licence is perpetual", + ), + ), + ("order_no", models.CharField(blank=True, null=True, max_length=50)), + ( + "price", + models.DecimalField( + blank=True, + default=0, + null=True, + decimal_places=2, + max_digits=10, + ), + ), + ( + "accounting_id", + models.CharField( + blank=True, + null=True, + help_text="Any value to help your accounting department identify this licence", + max_length=200, + ), + ), + ("provider", models.CharField(blank=True, null=True, max_length=100)), + ( + "invoice_no", + models.CharField( + blank=True, db_index=True, null=True, max_length=128 + ), + ), + ( + "license_details", + models.CharField( + verbose_name="License details", + blank=True, + default="", + max_length=1024, + ), + ), + ( + "base_objects", + models.ManyToManyField( + verbose_name="Assigned base objects", + through="licences.BaseObjectLicence", + to="assets.BaseObject", + related_name="_licence_base_objects_+", + ), + ), + ( + "budget_info", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + default=None, + to="assets.BudgetInfo", + blank=True, + null=True, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject', models.Model), + bases=( + ralph.lib.mixins.models.AdminAbsoluteUrlMixin, + "assets.baseobject", + models.Model, + ), ), migrations.CreateModel( - name='LicenceType', + name="LicenceType", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='LicenceUser', + name="LicenceUser", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('quantity', models.PositiveIntegerField(default=1)), - ('licence', models.ForeignKey(to='licences.Licence', on_delete=django.db.models.deletion.CASCADE)), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='licences', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("quantity", models.PositiveIntegerField(default=1)), + ( + "licence", + models.ForeignKey( + to="licences.Licence", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "user", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, + related_name="licences", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], ), migrations.CreateModel( - name='Software', + name="Software", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('asset_type', models.PositiveSmallIntegerField(choices=[(1, 'back office'), (2, 'data center'), (3, 'part'), (4, 'all')], default=4)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "asset_type", + models.PositiveSmallIntegerField( + choices=[ + (1, "back office"), + (2, "data center"), + (3, "part"), + (4, "all"), + ], + default=4, + ), + ), ], options={ - 'verbose_name_plural': 'software categories', + "verbose_name_plural": "software categories", }, ), migrations.AddField( - model_name='licence', - name='licence_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, help_text="Should be like 'per processor' or 'per machine' and so on. ", to='licences.LicenceType'), + model_name="licence", + name="licence_type", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + help_text="Should be like 'per processor' or 'per machine' and so on. ", + to="licences.LicenceType", + ), ), migrations.AddField( - model_name='licence', - name='manufacturer', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.Manufacturer', blank=True, null=True), + model_name="licence", + name="manufacturer", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="assets.Manufacturer", + blank=True, + null=True, + ), ), migrations.AddField( - model_name='licence', - name='office_infrastructure', - field=models.ForeignKey(to='back_office.OfficeInfrastructure', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="licence", + name="office_infrastructure", + field=models.ForeignKey( + to="back_office.OfficeInfrastructure", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='licence', - name='property_of', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.AssetHolder', blank=True, null=True), + model_name="licence", + name="property_of", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="assets.AssetHolder", + blank=True, + null=True, + ), ), migrations.AddField( - model_name='licence', - name='region', - field=models.ForeignKey(to='accounts.Region', on_delete=django.db.models.deletion.CASCADE), + model_name="licence", + name="region", + field=models.ForeignKey( + to="accounts.Region", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AddField( - model_name='licence', - name='software', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='licences.Software'), + model_name="licence", + name="software", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="licences.Software" + ), ), migrations.AddField( - model_name='licence', - name='users', - field=models.ManyToManyField(through='licences.LicenceUser', to=settings.AUTH_USER_MODEL, related_name='_licence_users_+'), + model_name="licence", + name="users", + field=models.ManyToManyField( + through="licences.LicenceUser", + to=settings.AUTH_USER_MODEL, + related_name="_licence_users_+", + ), ), migrations.AddField( - model_name='baseobjectlicence', - name='base_object', - field=models.ForeignKey(verbose_name='Asset', to='assets.BaseObject', related_name='licences', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectlicence", + name="base_object", + field=models.ForeignKey( + verbose_name="Asset", + to="assets.BaseObject", + related_name="licences", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='baseobjectlicence', - name='licence', - field=models.ForeignKey(to='licences.Licence', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectlicence", + name="licence", + field=models.ForeignKey( + to="licences.Licence", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AlterUniqueTogether( - name='licenceuser', - unique_together=set([('licence', 'user')]), + name="licenceuser", + unique_together=set([("licence", "user")]), ), migrations.AlterUniqueTogether( - name='baseobjectlicence', - unique_together=set([('licence', 'base_object')]), + name="baseobjectlicence", + unique_together=set([("licence", "base_object")]), ), ] diff --git a/src/ralph/licences/migrations/0002_auto_20151204_1325.py b/src/ralph/licences/migrations/0002_auto_20151204_1325.py index 6eb2c0a21d..e5f4c16eee 100644 --- a/src/ralph/licences/migrations/0002_auto_20151204_1325.py +++ b/src/ralph/licences/migrations/0002_auto_20151204_1325.py @@ -2,20 +2,24 @@ from __future__ import unicode_literals import django -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('licences', '0001_initial'), + ("licences", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='baseobjectlicence', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(related_name='licences', verbose_name='Asset', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectlicence", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + related_name="licences", + verbose_name="Asset", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/licences/migrations/0003_auto_20160823_0921.py b/src/ralph/licences/migrations/0003_auto_20160823_0921.py index 35dec4d570..27496c7101 100644 --- a/src/ralph/licences/migrations/0003_auto_20160823_0921.py +++ b/src/ralph/licences/migrations/0003_auto_20160823_0921.py @@ -5,40 +5,51 @@ class Migration(migrations.Migration): - dependencies = [ - ('licences', '0002_auto_20151204_1325'), + ("licences", "0002_auto_20151204_1325"), ] operations = [ migrations.AlterField( - model_name='licence', - name='base_objects', - field=models.ManyToManyField(to='assets.BaseObject', through='licences.BaseObjectLicence', verbose_name='assigned base objects', related_name='_licence_base_objects_+'), + model_name="licence", + name="base_objects", + field=models.ManyToManyField( + to="assets.BaseObject", + through="licences.BaseObjectLicence", + verbose_name="assigned base objects", + related_name="_licence_base_objects_+", + ), ), migrations.AlterField( - model_name='licence', - name='invoice_date', - field=models.DateField(null=True, blank=True, verbose_name='invoice date'), + model_name="licence", + name="invoice_date", + field=models.DateField(null=True, blank=True, verbose_name="invoice date"), ), migrations.AlterField( - model_name='licence', - name='license_details', - field=models.CharField(blank=True, verbose_name='license details', default='', max_length=1024), + model_name="licence", + name="license_details", + field=models.CharField( + blank=True, verbose_name="license details", default="", max_length=1024 + ), ), migrations.AlterField( - model_name='licence', - name='niw', - field=models.CharField(unique=True, verbose_name='inventory number', default='N/A', max_length=200), + model_name="licence", + name="niw", + field=models.CharField( + unique=True, + verbose_name="inventory number", + default="N/A", + max_length=200, + ), ), migrations.AlterField( - model_name='licence', - name='number_bought', - field=models.IntegerField(verbose_name='number of purchased items'), + model_name="licence", + name="number_bought", + field=models.IntegerField(verbose_name="number of purchased items"), ), migrations.AlterField( - model_name='licence', - name='sn', - field=models.TextField(null=True, blank=True, verbose_name='SN / key'), + model_name="licence", + name="sn", + field=models.TextField(null=True, blank=True, verbose_name="SN / key"), ), ] diff --git a/src/ralph/licences/migrations/0004_licence_depreciation_rate.py b/src/ralph/licences/migrations/0004_licence_depreciation_rate.py index 6b65ad8d80..9d217c6b23 100644 --- a/src/ralph/licences/migrations/0004_licence_depreciation_rate.py +++ b/src/ralph/licences/migrations/0004_licence_depreciation_rate.py @@ -5,15 +5,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('licences', '0003_auto_20160823_0921'), + ("licences", "0003_auto_20160823_0921"), ] operations = [ migrations.AddField( - model_name='licence', - name='depreciation_rate', - field=models.DecimalField(help_text='This value is in percentage. For example value: "100" means it depreciates during a year. Value: "25" means it depreciates during 4 years, and so on... .', default=50, null=True, decimal_places=2, max_digits=5, blank=True), + model_name="licence", + name="depreciation_rate", + field=models.DecimalField( + help_text='This value is in percentage. For example value: "100" means it depreciates during a year. Value: "25" means it depreciates during 4 years, and so on... .', + default=50, + null=True, + decimal_places=2, + max_digits=5, + blank=True, + ), ), ] diff --git a/src/ralph/licences/migrations/0005_licence_start_usage.py b/src/ralph/licences/migrations/0005_licence_start_usage.py index fb5d499ff9..54941eac43 100644 --- a/src/ralph/licences/migrations/0005_licence_start_usage.py +++ b/src/ralph/licences/migrations/0005_licence_start_usage.py @@ -5,15 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('licences', '0004_licence_depreciation_rate'), + ("licences", "0004_licence_depreciation_rate"), ] operations = [ migrations.AddField( - model_name='licence', - name='start_usage', - field=models.DateField(null=True, blank=True, help_text='Fill it if date of first usage is different then date of creation'), + model_name="licence", + name="start_usage", + field=models.DateField( + null=True, + blank=True, + help_text="Fill it if date of first usage is different then date of creation", + ), ), ] diff --git a/src/ralph/licences/migrations/0006_auto_20200909_1115.py b/src/ralph/licences/migrations/0006_auto_20200909_1115.py index 89187f7c39..cb7989a1fa 100644 --- a/src/ralph/licences/migrations/0006_auto_20200909_1115.py +++ b/src/ralph/licences/migrations/0006_auto_20200909_1115.py @@ -1,26 +1,227 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import djmoney.models.fields from decimal import Decimal class Migration(migrations.Migration): - dependencies = [ - ('licences', '0005_licence_start_usage'), + ("licences", "0005_licence_start_usage"), ] operations = [ migrations.AddField( - model_name='licence', - name='price_currency', - field=djmoney.models.fields.CurrencyField(max_length=3, default='XXX', editable=False, choices=[('XXX', '---'), ('AED', 'AED'), ('AFN', 'AFN'), ('ALL', 'ALL'), ('AMD', 'AMD'), ('ANG', 'ANG'), ('AOA', 'AOA'), ('ARS', 'ARS'), ('AUD', 'AUD'), ('AWG', 'AWG'), ('AZN', 'AZN'), ('BAM', 'BAM'), ('BBD', 'BBD'), ('BDT', 'BDT'), ('BGN', 'BGN'), ('BHD', 'BHD'), ('BIF', 'BIF'), ('BMD', 'BMD'), ('BND', 'BND'), ('BOB', 'BOB'), ('BOV', 'BOV'), ('BRL', 'BRL'), ('BSD', 'BSD'), ('BTN', 'BTN'), ('BWP', 'BWP'), ('BYN', 'BYN'), ('BYR', 'BYR'), ('BZD', 'BZD'), ('CAD', 'CAD'), ('CDF', 'CDF'), ('CHE', 'CHE'), ('CHF', 'CHF'), ('CHW', 'CHW'), ('CLF', 'CLF'), ('CLP', 'CLP'), ('CNY', 'CNY'), ('COP', 'COP'), ('COU', 'COU'), ('CRC', 'CRC'), ('CUC', 'CUC'), ('CUP', 'CUP'), ('CVE', 'CVE'), ('CZK', 'CZK'), ('DJF', 'DJF'), ('DKK', 'DKK'), ('DOP', 'DOP'), ('DZD', 'DZD'), ('EGP', 'EGP'), ('ERN', 'ERN'), ('ETB', 'ETB'), ('EUR', 'EUR'), ('FJD', 'FJD'), ('FKP', 'FKP'), ('GBP', 'GBP'), ('GEL', 'GEL'), ('GHS', 'GHS'), ('GIP', 'GIP'), ('GMD', 'GMD'), ('GNF', 'GNF'), ('GTQ', 'GTQ'), ('GYD', 'GYD'), ('HKD', 'HKD'), ('HNL', 'HNL'), ('HRK', 'HRK'), ('HTG', 'HTG'), ('HUF', 'HUF'), ('IDR', 'IDR'), ('ILS', 'ILS'), ('IMP', 'IMP'), ('INR', 'INR'), ('IQD', 'IQD'), ('IRR', 'IRR'), ('ISK', 'ISK'), ('JMD', 'JMD'), ('JOD', 'JOD'), ('JPY', 'JPY'), ('KES', 'KES'), ('KGS', 'KGS'), ('KHR', 'KHR'), ('KMF', 'KMF'), ('KPW', 'KPW'), ('KRW', 'KRW'), ('KWD', 'KWD'), ('KYD', 'KYD'), ('KZT', 'KZT'), ('LAK', 'LAK'), ('LBP', 'LBP'), ('LKR', 'LKR'), ('LRD', 'LRD'), ('LSL', 'LSL'), ('LTL', 'LTL'), ('LVL', 'LVL'), ('LYD', 'LYD'), ('MAD', 'MAD'), ('MDL', 'MDL'), ('MGA', 'MGA'), ('MKD', 'MKD'), ('MMK', 'MMK'), ('MNT', 'MNT'), ('MOP', 'MOP'), ('MRO', 'MRO'), ('MUR', 'MUR'), ('MVR', 'MVR'), ('MWK', 'MWK'), ('MXN', 'MXN'), ('MXV', 'MXV'), ('MYR', 'MYR'), ('MZN', 'MZN'), ('NAD', 'NAD'), ('NGN', 'NGN'), ('NIO', 'NIO'), ('NOK', 'NOK'), ('NPR', 'NPR'), ('NZD', 'NZD'), ('OMR', 'OMR'), ('PAB', 'PAB'), ('PEN', 'PEN'), ('PGK', 'PGK'), ('PHP', 'PHP'), ('PKR', 'PKR'), ('PLN', 'PLN'), ('PYG', 'PYG'), ('QAR', 'QAR'), ('RON', 'RON'), ('RSD', 'RSD'), ('RUB', 'RUB'), ('RWF', 'RWF'), ('SAR', 'SAR'), ('SBD', 'SBD'), ('SCR', 'SCR'), ('SDG', 'SDG'), ('SEK', 'SEK'), ('SGD', 'SGD'), ('SHP', 'SHP'), ('SLL', 'SLL'), ('SOS', 'SOS'), ('SRD', 'SRD'), ('SSP', 'SSP'), ('STD', 'STD'), ('SVC', 'SVC'), ('SYP', 'SYP'), ('SZL', 'SZL'), ('THB', 'THB'), ('TJS', 'TJS'), ('TMM', 'TMM'), ('TMT', 'TMT'), ('TND', 'TND'), ('TOP', 'TOP'), ('TRY', 'TRY'), ('TTD', 'TTD'), ('TVD', 'TVD'), ('TWD', 'TWD'), ('TZS', 'TZS'), ('UAH', 'UAH'), ('UGX', 'UGX'), ('USD', 'USD'), ('USN', 'USN'), ('UYI', 'UYI'), ('UYU', 'UYU'), ('UZS', 'UZS'), ('VEF', 'VEF'), ('VND', 'VND'), ('VUV', 'VUV'), ('WST', 'WST'), ('XAF', 'XAF'), ('XAG', 'XAG'), ('XAU', 'XAU'), ('XBA', 'XBA'), ('XBB', 'XBB'), ('XBC', 'XBC'), ('XBD', 'XBD'), ('XCD', 'XCD'), ('XDR', 'XDR'), ('XFO', 'XFO'), ('XFU', 'XFU'), ('XOF', 'XOF'), ('XPD', 'XPD'), ('XPF', 'XPF'), ('XPT', 'XPT'), ('XSU', 'XSU'), ('XTS', 'XTS'), ('XUA', 'XUA'), ('XYZ', 'XYZ'), ('YER', 'YER'), ('ZAR', 'ZAR'), ('ZMK', 'ZMK'), ('ZMW', 'ZMW'), ('ZWD', 'ZWD'), ('ZWL', 'ZWL'), ('ZWN', 'ZWN')]), + model_name="licence", + name="price_currency", + field=djmoney.models.fields.CurrencyField( + max_length=3, + default="XXX", + editable=False, + choices=[ + ("XXX", "---"), + ("AED", "AED"), + ("AFN", "AFN"), + ("ALL", "ALL"), + ("AMD", "AMD"), + ("ANG", "ANG"), + ("AOA", "AOA"), + ("ARS", "ARS"), + ("AUD", "AUD"), + ("AWG", "AWG"), + ("AZN", "AZN"), + ("BAM", "BAM"), + ("BBD", "BBD"), + ("BDT", "BDT"), + ("BGN", "BGN"), + ("BHD", "BHD"), + ("BIF", "BIF"), + ("BMD", "BMD"), + ("BND", "BND"), + ("BOB", "BOB"), + ("BOV", "BOV"), + ("BRL", "BRL"), + ("BSD", "BSD"), + ("BTN", "BTN"), + ("BWP", "BWP"), + ("BYN", "BYN"), + ("BYR", "BYR"), + ("BZD", "BZD"), + ("CAD", "CAD"), + ("CDF", "CDF"), + ("CHE", "CHE"), + ("CHF", "CHF"), + ("CHW", "CHW"), + ("CLF", "CLF"), + ("CLP", "CLP"), + ("CNY", "CNY"), + ("COP", "COP"), + ("COU", "COU"), + ("CRC", "CRC"), + ("CUC", "CUC"), + ("CUP", "CUP"), + ("CVE", "CVE"), + ("CZK", "CZK"), + ("DJF", "DJF"), + ("DKK", "DKK"), + ("DOP", "DOP"), + ("DZD", "DZD"), + ("EGP", "EGP"), + ("ERN", "ERN"), + ("ETB", "ETB"), + ("EUR", "EUR"), + ("FJD", "FJD"), + ("FKP", "FKP"), + ("GBP", "GBP"), + ("GEL", "GEL"), + ("GHS", "GHS"), + ("GIP", "GIP"), + ("GMD", "GMD"), + ("GNF", "GNF"), + ("GTQ", "GTQ"), + ("GYD", "GYD"), + ("HKD", "HKD"), + ("HNL", "HNL"), + ("HRK", "HRK"), + ("HTG", "HTG"), + ("HUF", "HUF"), + ("IDR", "IDR"), + ("ILS", "ILS"), + ("IMP", "IMP"), + ("INR", "INR"), + ("IQD", "IQD"), + ("IRR", "IRR"), + ("ISK", "ISK"), + ("JMD", "JMD"), + ("JOD", "JOD"), + ("JPY", "JPY"), + ("KES", "KES"), + ("KGS", "KGS"), + ("KHR", "KHR"), + ("KMF", "KMF"), + ("KPW", "KPW"), + ("KRW", "KRW"), + ("KWD", "KWD"), + ("KYD", "KYD"), + ("KZT", "KZT"), + ("LAK", "LAK"), + ("LBP", "LBP"), + ("LKR", "LKR"), + ("LRD", "LRD"), + ("LSL", "LSL"), + ("LTL", "LTL"), + ("LVL", "LVL"), + ("LYD", "LYD"), + ("MAD", "MAD"), + ("MDL", "MDL"), + ("MGA", "MGA"), + ("MKD", "MKD"), + ("MMK", "MMK"), + ("MNT", "MNT"), + ("MOP", "MOP"), + ("MRO", "MRO"), + ("MUR", "MUR"), + ("MVR", "MVR"), + ("MWK", "MWK"), + ("MXN", "MXN"), + ("MXV", "MXV"), + ("MYR", "MYR"), + ("MZN", "MZN"), + ("NAD", "NAD"), + ("NGN", "NGN"), + ("NIO", "NIO"), + ("NOK", "NOK"), + ("NPR", "NPR"), + ("NZD", "NZD"), + ("OMR", "OMR"), + ("PAB", "PAB"), + ("PEN", "PEN"), + ("PGK", "PGK"), + ("PHP", "PHP"), + ("PKR", "PKR"), + ("PLN", "PLN"), + ("PYG", "PYG"), + ("QAR", "QAR"), + ("RON", "RON"), + ("RSD", "RSD"), + ("RUB", "RUB"), + ("RWF", "RWF"), + ("SAR", "SAR"), + ("SBD", "SBD"), + ("SCR", "SCR"), + ("SDG", "SDG"), + ("SEK", "SEK"), + ("SGD", "SGD"), + ("SHP", "SHP"), + ("SLL", "SLL"), + ("SOS", "SOS"), + ("SRD", "SRD"), + ("SSP", "SSP"), + ("STD", "STD"), + ("SVC", "SVC"), + ("SYP", "SYP"), + ("SZL", "SZL"), + ("THB", "THB"), + ("TJS", "TJS"), + ("TMM", "TMM"), + ("TMT", "TMT"), + ("TND", "TND"), + ("TOP", "TOP"), + ("TRY", "TRY"), + ("TTD", "TTD"), + ("TVD", "TVD"), + ("TWD", "TWD"), + ("TZS", "TZS"), + ("UAH", "UAH"), + ("UGX", "UGX"), + ("USD", "USD"), + ("USN", "USN"), + ("UYI", "UYI"), + ("UYU", "UYU"), + ("UZS", "UZS"), + ("VEF", "VEF"), + ("VND", "VND"), + ("VUV", "VUV"), + ("WST", "WST"), + ("XAF", "XAF"), + ("XAG", "XAG"), + ("XAU", "XAU"), + ("XBA", "XBA"), + ("XBB", "XBB"), + ("XBC", "XBC"), + ("XBD", "XBD"), + ("XCD", "XCD"), + ("XDR", "XDR"), + ("XFO", "XFO"), + ("XFU", "XFU"), + ("XOF", "XOF"), + ("XPD", "XPD"), + ("XPF", "XPF"), + ("XPT", "XPT"), + ("XSU", "XSU"), + ("XTS", "XTS"), + ("XUA", "XUA"), + ("XYZ", "XYZ"), + ("YER", "YER"), + ("ZAR", "ZAR"), + ("ZMK", "ZMK"), + ("ZMW", "ZMW"), + ("ZWD", "ZWD"), + ("ZWL", "ZWL"), + ("ZWN", "ZWN"), + ], + ), ), migrations.AlterField( - model_name='licence', - name='price', - field=djmoney.models.fields.MoneyField(null=True, default=Decimal('0'), max_digits=15, decimal_places=2, default_currency='XXX'), + model_name="licence", + name="price", + field=djmoney.models.fields.MoneyField( + null=True, + default=Decimal("0"), + max_digits=15, + decimal_places=2, + default_currency="XXX", + ), ), ] diff --git a/src/ralph/licences/migrations/0007_auto_20240506_1633.py b/src/ralph/licences/migrations/0007_auto_20240506_1633.py index ed4b7e13b8..bc663e0aea 100644 --- a/src/ralph/licences/migrations/0007_auto_20240506_1633.py +++ b/src/ralph/licences/migrations/0007_auto_20240506_1633.py @@ -7,16 +7,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('licences', '0006_auto_20200909_1115'), + ("licences", "0006_auto_20200909_1115"), ] operations = [ migrations.AlterModelManagers( - name='licence', + name="licence", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/licences/migrations/0008_auto_20240628_1207.py b/src/ralph/licences/migrations/0008_auto_20240628_1207.py index 6faf0b4ba3..9b6a192d8a 100644 --- a/src/ralph/licences/migrations/0008_auto_20240628_1207.py +++ b/src/ralph/licences/migrations/0008_auto_20240628_1207.py @@ -6,15 +6,25 @@ class Migration(migrations.Migration): - dependencies = [ - ('licences', '0007_auto_20240506_1633'), + ("licences", "0007_auto_20240506_1633"), ] operations = [ migrations.AlterField( - model_name='baseobjectlicence', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_models=['back_office.BackOfficeAsset', 'data_center.DataCenterAsset', 'virtual.VirtualServer', 'data_center.Cluster'], on_delete=django.db.models.deletion.CASCADE, related_name='licences', to='assets.BaseObject', verbose_name='Asset'), + model_name="baseobjectlicence", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_models=[ + "back_office.BackOfficeAsset", + "data_center.DataCenterAsset", + "virtual.VirtualServer", + "data_center.Cluster", + ], + on_delete=django.db.models.deletion.CASCADE, + related_name="licences", + to="assets.BaseObject", + verbose_name="Asset", + ), ), ] diff --git a/src/ralph/licences/models.py b/src/ralph/licences/models.py index c6af79886e..2399cfde96 100644 --- a/src/ralph/licences/models.py +++ b/src/ralph/licences/models.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """SAM module models.""" + from django.conf import settings from django.core.exceptions import ValidationError from django.db import models @@ -14,11 +15,7 @@ from ralph.assets.models.base import BaseObject from ralph.assets.models.choices import ObjectModelType from ralph.lib.mixins.fields import BaseObjectForeignKey -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - PriceMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, PriceMixin from ralph.lib.permissions.models import PermByFieldMixin from ralph.lib.polymorphic.models import PolymorphicQuerySet @@ -30,13 +27,7 @@ """ -class LicenceType( - AdminAbsoluteUrlMixin, - PermByFieldMixin, - NamedMixin, - models.Model -): - +class LicenceType(AdminAbsoluteUrlMixin, PermByFieldMixin, NamedMixin, models.Model): """The type of a licence""" @classmethod @@ -44,14 +35,9 @@ def create_from_string(cls, string_name, *args, **kwargs): return cls(name=string_name) -class Software( - AdminAbsoluteUrlMixin, - PermByFieldMixin, - NamedMixin, - models.Model -): - +class Software(AdminAbsoluteUrlMixin, PermByFieldMixin, NamedMixin, models.Model): """The category of the licensed software""" + _allow_in_dashboard = True asset_type = models.PositiveSmallIntegerField( @@ -69,7 +55,7 @@ def licences(self): yield licence class Meta: - verbose_name_plural = _('software categories') + verbose_name_plural = _("software categories") class LicencesUsedFreeManager(models.Manager): @@ -84,8 +70,8 @@ def get_queryset(self): # about default value for Sum id_column = Licence.baseobject_ptr.field.column - user_quantity_field = Licence.users.through._meta.get_field('quantity') - user_licence_field = Licence.users.through._meta.get_field('licence') + user_quantity_field = Licence.users.through._meta.get_field("quantity") + user_licence_field = Licence.users.through._meta.get_field("licence") user_count_query = _SELECT_USED_LICENCES_QUERY.format( assignment_table=Licence.users.through._meta.db_table, quantity_column=user_quantity_field.db_column or user_quantity_field.column, # noqa @@ -94,35 +80,45 @@ def get_queryset(self): id_column=id_column, ) - base_object_quantity_field = Licence.base_objects.through._meta.get_field('quantity') # noqa - base_object_licence_field = Licence.base_objects.through._meta.get_field('licence') # noqa + base_object_quantity_field = Licence.base_objects.through._meta.get_field( + "quantity" + ) # noqa + base_object_licence_field = Licence.base_objects.through._meta.get_field( + "licence" + ) # noqa base_object_count_query = _SELECT_USED_LICENCES_QUERY.format( assignment_table=Licence.base_objects.through._meta.db_table, - quantity_column=base_object_quantity_field.db_column or base_object_quantity_field.column, # noqa - licence_id_column=base_object_licence_field.db_column or base_object_licence_field.column, # noqa + quantity_column=base_object_quantity_field.db_column + or base_object_quantity_field.column, # noqa + licence_id_column=base_object_licence_field.db_column + or base_object_licence_field.column, # noqa licence_table=Licence._meta.db_table, id_column=id_column, ) - return super().get_queryset().extra( - select={ - 'user_count': user_count_query, - 'baseobject_count': base_object_count_query, - } + return ( + super() + .get_queryset() + .extra( + select={ + "user_count": user_count_query, + "baseobject_count": base_object_count_query, + } + ) ) LICENCES_RELATED_OBJECTS_PREFETCH_RELATED = [ - 'users', + "users", # prefetch all baseobjects related with licence; this allows to call # [bol.base_object for bol in licence.baseobjectlicence_set.all()] # without additional queries Prefetch( - 'baseobjectlicence_set__base_object', + "baseobjectlicence_set__base_object", # polymorphic manager is used to get final instance of the object # (ex. DataCenterAsset) - queryset=BaseObject.polymorphic_objects.all() - ) + queryset=BaseObject.polymorphic_objects.all(), + ), ] @@ -130,9 +126,12 @@ class LicencesRelatedObjectsManager(models.Manager): """ Prefetch related objects by-default """ + def get_queryset(self): - return super().get_queryset().prefetch_related( - *LICENCES_RELATED_OBJECTS_PREFETCH_RELATED + return ( + super() + .get_queryset() + .prefetch_related(*LICENCES_RELATED_OBJECTS_PREFETCH_RELATED) ) @@ -143,8 +142,8 @@ class LicencesUsedFreeRelatedObjectsManager( class Licence(Regionalizable, AdminAbsoluteUrlMixin, PriceMixin, BaseObject): - """A set of licences for a single software with a single expiration date""" + _allow_in_dashboard = True manufacturer = models.ForeignKey( @@ -171,22 +170,22 @@ class Licence(Regionalizable, AdminAbsoluteUrlMixin, PriceMixin, BaseObject): on_delete=models.PROTECT, ) number_bought = models.IntegerField( - verbose_name=_('number of purchased items'), + verbose_name=_("number of purchased items"), ) sn = models.TextField( - verbose_name=_('SN / key'), + verbose_name=_("SN / key"), null=True, blank=True, ) niw = models.CharField( max_length=200, - verbose_name=_('inventory number'), + verbose_name=_("inventory number"), null=False, unique=True, - default='N/A', + default="N/A", ) invoice_date = models.DateField( - verbose_name=_('invoice date'), + verbose_name=_("invoice date"), null=True, blank=True, ) @@ -203,7 +202,7 @@ class Licence(Regionalizable, AdminAbsoluteUrlMixin, PriceMixin, BaseObject): decimal_places=2, default=settings.DEFAULT_LICENCE_DEPRECIATION_RATE, help_text=_( - 'This value is in percentage.' + "This value is in percentage." ' For example value: "100" means it depreciates during a year.' ' Value: "25" means it depreciates during 4 years, and so on... .' ), @@ -214,33 +213,31 @@ class Licence(Regionalizable, AdminAbsoluteUrlMixin, PriceMixin, BaseObject): null=True, blank=True, help_text=_( - 'Any value to help your accounting department ' - 'identify this licence' + "Any value to help your accounting department " "identify this licence" ), ) base_objects = models.ManyToManyField( BaseObject, - verbose_name=_('assigned base objects'), - through='BaseObjectLicence', - related_name='+', + verbose_name=_("assigned base objects"), + through="BaseObjectLicence", + related_name="+", ) users = models.ManyToManyField( - settings.AUTH_USER_MODEL, - through='LicenceUser', - related_name='+' + settings.AUTH_USER_MODEL, through="LicenceUser", related_name="+" ) provider = models.CharField(max_length=100, null=True, blank=True) - invoice_no = models.CharField( - max_length=128, db_index=True, null=True, blank=True - ) + invoice_no = models.CharField(max_length=128, db_index=True, null=True, blank=True) license_details = models.CharField( - verbose_name=_('license details'), + verbose_name=_("license details"), max_length=1024, blank=True, - default='', + default="", ) office_infrastructure = models.ForeignKey( - 'back_office.OfficeInfrastructure', null=True, blank=True, on_delete=models.CASCADE + "back_office.OfficeInfrastructure", + null=True, + blank=True, + on_delete=models.CASCADE, ) budget_info = models.ForeignKey( BudgetInfo, @@ -252,9 +249,7 @@ class Licence(Regionalizable, AdminAbsoluteUrlMixin, PriceMixin, BaseObject): start_usage = models.DateField( blank=True, null=True, - help_text=( - 'Fill it if date of first usage is different then date of creation' - ) + help_text=("Fill it if date of first usage is different then date of creation"), ) polymorphic_objects = PolymorphicQuerySet.as_manager() @@ -288,22 +283,23 @@ def used(self): # try use fields from objects_used_free manager return (self.user_count or 0) + (self.baseobject_count or 0) except AttributeError: - base_objects_qs = self.base_objects.through.objects.filter( - licence=self - ) + base_objects_qs = self.base_objects.through.objects.filter(licence=self) users_qs = self.users.through.objects.filter(licence=self) def get_sum(qs): - return qs.aggregate(sum=Sum('quantity'))['sum'] or 0 + return qs.aggregate(sum=Sum("quantity"))["sum"] or 0 + return sum(map(get_sum, [base_objects_qs, users_qs])) - used._permission_field = 'number_bought' + + used._permission_field = "number_bought" @cached_property def free(self): if not self.pk: return 0 return self.number_bought - self.used - free._permission_field = 'number_bought' + + free._permission_field = "number_bought" @classmethod def get_autocomplete_queryset(cls): @@ -319,52 +315,47 @@ class BaseObjectLicence(models.Model): licence = models.ForeignKey(Licence, on_delete=models.CASCADE) base_object = BaseObjectForeignKey( BaseObject, - related_name='licences', - verbose_name=_('Asset'), + related_name="licences", + verbose_name=_("Asset"), limit_models=[ - 'back_office.BackOfficeAsset', - 'data_center.DataCenterAsset', - 'virtual.VirtualServer', - 'data_center.Cluster', + "back_office.BackOfficeAsset", + "data_center.DataCenterAsset", + "virtual.VirtualServer", + "data_center.Cluster", ], - on_delete=models.CASCADE + on_delete=models.CASCADE, ) quantity = models.PositiveIntegerField(default=1) class Meta: - unique_together = ('licence', 'base_object') + unique_together = ("licence", "base_object") def __str__(self): - return '{} of {} assigned to {}'.format( + return "{} of {} assigned to {}".format( self.quantity, self.licence, self.base_object ) def clean(self): - bo_asset = getattr_dunder( - self.base_object, 'asset__backofficeasset' - ) - if ( - bo_asset and self.licence and - self.licence.region_id != bo_asset.region_id - ): + bo_asset = getattr_dunder(self.base_object, "asset__backofficeasset") + if bo_asset and self.licence and self.licence.region_id != bo_asset.region_id: raise ValidationError( - _('Asset region is in a different region than licence.') + _("Asset region is in a different region than licence.") ) class LicenceUser(models.Model): licence = models.ForeignKey(Licence, on_delete=models.CASCADE) user = models.ForeignKey( - settings.AUTH_USER_MODEL, - related_name='licences', - on_delete=models.CASCADE + settings.AUTH_USER_MODEL, related_name="licences", on_delete=models.CASCADE ) quantity = models.PositiveIntegerField(default=1) class Meta: - unique_together = ('licence', 'user') + unique_together = ("licence", "user") def __str__(self): - return '{} of {} assigned to {}'.format( - self.quantity, self.licence, self.user, + return "{} of {} assigned to {}".format( + self.quantity, + self.licence, + self.user, ) diff --git a/src/ralph/licences/tests/factories.py b/src/ralph/licences/tests/factories.py index d634c55299..e6c1dd9b98 100644 --- a/src/ralph/licences/tests/factories.py +++ b/src/ralph/licences/tests/factories.py @@ -13,11 +13,11 @@ from ralph.assets.tests.factories import ( AssetHolderFactory, BudgetInfoFactory, - ManufacturerFactory + ManufacturerFactory, ) from ralph.back_office.tests.factories import ( BackOfficeAssetFactory, - OfficeInfrastructureFactory + OfficeInfrastructureFactory, ) from ralph.data_center.tests.factories import DataCenterAssetFactory from ralph.licences.models import ( @@ -25,34 +25,37 @@ Licence, LicenceType, LicenceUser, - Software + Software, ) date_now = datetime.now().date() class LicenceTypeFactory(DjangoModelFactory): - - name = factory.Iterator([ - 'per user', 'per install', 'msdn', 'disk drive', 'vl (per core)' - ]) + name = factory.Iterator( + ["per user", "per install", "msdn", "disk drive", "vl (per core)"] + ) class Meta: model = LicenceType - django_get_or_create = ['name'] + django_get_or_create = ["name"] class SoftwareFactory(DjangoModelFactory): - - name = factory.Iterator([ - 'MS EA CoreCal', 'DB Boost', 'Twilio', 'Infographics', - 'Oracle Business Intelligence Server Administrator', - 'Oracle Advanced Compression' - ]) + name = factory.Iterator( + [ + "MS EA CoreCal", + "DB Boost", + "Twilio", + "Infographics", + "Oracle Business Intelligence Server Administrator", + "Oracle Advanced Compression", + ] + ) class Meta: model = Software - django_get_or_create = ['name'] + django_get_or_create = ["name"] class MoneyProvider(BaseProvider): @@ -64,7 +67,6 @@ def money(self): class LicenceFactory(DjangoModelFactory): - licence_type = factory.SubFactory(LicenceTypeFactory) software = factory.SubFactory(SoftwareFactory) region = factory.SubFactory(RegionFactory) @@ -73,14 +75,14 @@ class LicenceFactory(DjangoModelFactory): number_bought = 10 invoice_date = date_now - timedelta(days=15) valid_thru = date_now + timedelta(days=365) - invoice_no = factory.Sequence(lambda n: 'Invoice number ' + str(n)) + invoice_no = factory.Sequence(lambda n: "Invoice number " + str(n)) budget_info = factory.SubFactory(BudgetInfoFactory) - sn = factory.Faker('ssn') - order_no = factory.Sequence(lambda n: 'Order number ' + str(n)) + sn = factory.Faker("ssn") + order_no = factory.Sequence(lambda n: "Order number " + str(n)) property_of = factory.SubFactory(AssetHolderFactory) office_infrastructure = factory.SubFactory(OfficeInfrastructureFactory) - depreciation_rate = '100.00' - price = factory.Faker('money') + depreciation_rate = "100.00" + price = factory.Faker("money") class Meta: model = Licence @@ -115,5 +117,5 @@ class Meta: class LicenceWithUserAndBaseObjectsFactory(LicenceFactory): - users = factory.RelatedFactory(LicenceUserFactory, 'licence') - base_objects = factory.RelatedFactory(BaseObjectLicenceFactory, 'licence') + users = factory.RelatedFactory(LicenceUserFactory, "licence") + base_objects = factory.RelatedFactory(BaseObjectLicenceFactory, "licence") diff --git a/src/ralph/licences/tests/test_api.py b/src/ralph/licences/tests/test_api.py index 2185e7eea5..d074568942 100644 --- a/src/ralph/licences/tests/test_api.py +++ b/src/ralph/licences/tests/test_api.py @@ -14,7 +14,7 @@ class LicenceAPITests(RalphAPITestCase): def setUp(self): super().setUp() self.licence1, self.licence2 = LicenceFactory.create_batch(2) - region_pl = RegionFactory(name='pl') + region_pl = RegionFactory(name="pl") self.licence3 = LicenceFactory(region=region_pl) self.base_object = BackOfficeAssetFactory() self.base_object2 = BackOfficeAssetFactory(region=region_pl) @@ -26,86 +26,73 @@ def setUp(self): self.licence4 = LicenceFactory(service_env=self.service_env) def test_get_licence_list(self): - url = reverse('licence-list') - response = self.client.get(url, format='json') + url = reverse("licence-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], Licence.objects.count()) + self.assertEqual(response.data["count"], Licence.objects.count()) def test_get_licence_with_user_details(self): - url = reverse('licence-detail', args=(self.licence1.id,)) - response = self.client.get(url, format='json') + url = reverse("licence-detail", args=(self.licence1.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["number_bought"], self.licence1.number_bought) + self.assertEqual(response.data["region"]["id"], self.licence1.region.id) self.assertEqual( - response.data['number_bought'], self.licence1.number_bought + response.data["manufacturer"]["id"], self.licence1.manufacturer.id ) self.assertEqual( - response.data['region']['id'], self.licence1.region.id + response.data["licence_type"]["id"], self.licence1.licence_type.id ) + self.assertEqual(response.data["software"]["id"], self.licence1.software.id) self.assertEqual( - response.data['manufacturer']['id'], self.licence1.manufacturer.id + response.data["users"][0]["user"]["id"], + self.user1.id, ) self.assertEqual( - response.data['licence_type']['id'], self.licence1.licence_type.id - ) - self.assertEqual( - response.data['software']['id'], self.licence1.software.id - ) - self.assertEqual( - response.data['users'][0]['user']['id'], self.user1.id, - ) - self.assertEqual( - response.data['depreciation_rate'], self.licence1.depreciation_rate + response.data["depreciation_rate"], self.licence1.depreciation_rate ) def test_get_licence_with_service_env(self): - url = reverse('licence-detail', args=(self.licence4.id,)) - response = self.client.get(url, format='json') + url = reverse("licence-detail", args=(self.licence4.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["service_env"]["id"], self.service_env.id) self.assertEqual( - response.data['service_env']['id'], self.service_env.id - ) - self.assertEqual( - response.data['service_env']['service'], - self.service_env.service.name + response.data["service_env"]["service"], self.service_env.service.name ) self.assertEqual( - response.data['service_env']['environment'], - self.service_env.environment.name + response.data["service_env"]["environment"], + self.service_env.environment.name, ) def test_get_licence_with_base_object_details(self): - url = reverse('licence-detail', args=(self.licence2.id,)) - response = self.client.get(url, format='json') + url = reverse("licence-detail", args=(self.licence2.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue( - response.data['base_objects'][0]['base_object'].endswith( - reverse('baseobject-detail', args=(self.base_object.id,)) + response.data["base_objects"][0]["base_object"].endswith( + reverse("baseobject-detail", args=(self.base_object.id,)) ) ) def test_api_region_validate_error(self): - url = reverse('baseobjectlicence-list') - data = { - "base_object": self.base_object.id, - "licence": self.licence1.id - } - response = self.client.post(url, data=data, format='json') + url = reverse("baseobjectlicence-list") + data = {"base_object": self.base_object.id, "licence": self.licence1.id} + response = self.client.post(url, data=data, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( - response.data['non_field_errors'], - ['Asset region is in a different region than licence.'] + response.data["non_field_errors"], + ["Asset region is in a different region than licence."], ) def test_api_region_validate_ok(self): - url = reverse('baseobjectlicence-list') - data = { - "base_object": self.base_object2.id, - "licence": self.licence3.id - } - response = self.client.post(url, data=data, format='json') + url = reverse("baseobjectlicence-list") + data = {"base_object": self.base_object2.id, "licence": self.licence3.id} + response = self.client.post(url, data=data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertTrue(BaseObjectLicence.objects.filter( - base_object=self.base_object2.id, - licence=self.licence3.id - ).exists()) + self.assertTrue( + BaseObjectLicence.objects.filter( + base_object=self.base_object2.id, licence=self.licence3.id + ).exists() + ) diff --git a/src/ralph/licences/tests/test_functional.py b/src/ralph/licences/tests/test_functional.py index 589d3fcdb9..3dbb9120c9 100644 --- a/src/ralph/licences/tests/test_functional.py +++ b/src/ralph/licences/tests/test_functional.py @@ -12,12 +12,11 @@ class BaseObjectLicenceTest(ClientMixin, TestCase): - def setUp(self): # noqa super().setUp() self.login_as_user() - region_pl = RegionFactory(name='pl') - region_de = RegionFactory(name='de') + region_pl = RegionFactory(name="pl") + region_de = RegionFactory(name="de") self.licence = LicenceFactory(region=region_pl) self.bo_1 = BackOfficeAssetFactory(region=region_pl) self.bo_2 = BackOfficeAssetFactory(region=region_de) @@ -25,29 +24,27 @@ def setUp(self): # noqa def test_create_new_licence(self): service_env = ServiceEnvironmentFactory() data = { - 'licence_type': self.licence.licence_type.id, - 'software': self.licence.software.id, - 'niw': '111', - 'region': self.licence.region.id, - 'price_0': 100, - 'price_1': 'PLN', - 'number_bought': 3, - 'service_env': service_env.id, - 'custom_fields-customfieldvalue-content_type-object_id-TOTAL_FORMS': 3, - 'custom_fields-customfieldvalue-content_type-object_id-INITIAL_FORMS': 0, - 'custom_fields-customfieldvalue-content_type-object_id-MIN_NUM_FORMS': 0, - 'custom_fields-customfieldvalue-content_type-object_id-MAX_NUM_FORMS': 1000, + "licence_type": self.licence.licence_type.id, + "software": self.licence.software.id, + "niw": "111", + "region": self.licence.region.id, + "price_0": 100, + "price_1": "PLN", + "number_bought": 3, + "service_env": service_env.id, + "custom_fields-customfieldvalue-content_type-object_id-TOTAL_FORMS": 3, + "custom_fields-customfieldvalue-content_type-object_id-INITIAL_FORMS": 0, + "custom_fields-customfieldvalue-content_type-object_id-MIN_NUM_FORMS": 0, + "custom_fields-customfieldvalue-content_type-object_id-MAX_NUM_FORMS": 1000, } response = self.client.post( - reverse('admin:licences_licence_add'), - data=data, - follow=True + reverse("admin:licences_licence_add"), data=data, follow=True ) - new_licence = Licence.objects.get(niw='111') + new_licence = Licence.objects.get(niw="111") self.assertEqual(response.status_code, 200) - self.assertNotIn('errors', response.context_data) + self.assertNotIn("errors", response.context_data) self.assertEqual(new_licence.licence_type, self.licence.licence_type) self.assertEqual(new_licence.software, self.licence.software) self.assertEqual(new_licence.region, self.licence.region) @@ -58,21 +55,19 @@ def test_create_new_licence(self): def test_add_base_object_licence_ok(self): data = { - 'baseobjectlicence_set-TOTAL_FORMS': 1, - 'baseobjectlicence_set-INITIAL_FORMS': 0, - 'baseobjectlicence_set-MIN_NUM_FORMS': 0, - 'baseobjectlicence_set-MAX_NUM_FORMS': 1000, - 'baseobjectlicence_set-0-id': '', - 'baseobjectlicence_set-0-licence': self.licence.id, - 'baseobjectlicence_set-0-base_object': self.bo_1.id, - 'baseobjectlicence_set-0-quantity': 1, + "baseobjectlicence_set-TOTAL_FORMS": 1, + "baseobjectlicence_set-INITIAL_FORMS": 0, + "baseobjectlicence_set-MIN_NUM_FORMS": 0, + "baseobjectlicence_set-MAX_NUM_FORMS": 1000, + "baseobjectlicence_set-0-id": "", + "baseobjectlicence_set-0-licence": self.licence.id, + "baseobjectlicence_set-0-base_object": self.bo_1.id, + "baseobjectlicence_set-0-quantity": 1, } response = self.client.post( - reverse( - 'admin:licences_licence_assignments', args=(self.licence.id,) - ), + reverse("admin:licences_licence_assignments", args=(self.licence.id,)), data=data, - follow=True + follow=True, ) self.assertEqual(response.status_code, 200) base_object_licence = BaseObjectLicence.objects.filter( @@ -82,22 +77,20 @@ def test_add_base_object_licence_ok(self): def test_add_base_object_licence_error(self): data = { - 'baseobjectlicence_set-TOTAL_FORMS': 1, - 'baseobjectlicence_set-INITIAL_FORMS': 0, - 'baseobjectlicence_set-MIN_NUM_FORMS': 0, - 'baseobjectlicence_set-MAX_NUM_FORMS': 1000, - 'baseobjectlicence_set-0-id': '', - 'baseobjectlicence_set-0-licence': self.licence.id, - 'baseobjectlicence_set-0-base_object': self.bo_2.id, - 'baseobjectlicence_set-0-quantity': 1, + "baseobjectlicence_set-TOTAL_FORMS": 1, + "baseobjectlicence_set-INITIAL_FORMS": 0, + "baseobjectlicence_set-MIN_NUM_FORMS": 0, + "baseobjectlicence_set-MAX_NUM_FORMS": 1000, + "baseobjectlicence_set-0-id": "", + "baseobjectlicence_set-0-licence": self.licence.id, + "baseobjectlicence_set-0-base_object": self.bo_2.id, + "baseobjectlicence_set-0-quantity": 1, } response = self.client.post( - reverse( - 'admin:licences_licence_assignments', args=(self.licence.id,) - ), + reverse("admin:licences_licence_assignments", args=(self.licence.id,)), data=data, - follow=True + follow=True, ) self.assertContains( - response, 'Asset region is in a different region than licence.' + response, "Asset region is in a different region than licence." ) diff --git a/src/ralph/licences/tests/tests_models.py b/src/ralph/licences/tests/tests_models.py index a5ad0306ff..a42ceb65c4 100644 --- a/src/ralph/licences/tests/tests_models.py +++ b/src/ralph/licences/tests/tests_models.py @@ -12,11 +12,10 @@ class BaseObjectLicenceCleanTest(RalphTestCase): - def setUp(self): super().setUp() - self.region_pl = RegionFactory(name='pl') - self.region_de = RegionFactory(name='de') + self.region_pl = RegionFactory(name="pl") + self.region_de = RegionFactory(name="de") self.licence_de = LicenceFactory(region=self.region_de) self.bo_asset = BackOfficeAssetFactory(region=self.region_pl) @@ -25,10 +24,7 @@ def test_region_validate(self): base_object_licence.licence = self.licence_de base_object_licence.base_object = self.bo_asset with self.assertRaisesRegex( - ValidationError, - ( - 'Asset region is in a different region than licence.' - ) + ValidationError, ("Asset region is in a different region than licence.") ): base_object_licence.clean() @@ -44,25 +40,21 @@ def setUp(self): def test_get_autocomplete_queryset(self): with self.assertNumQueries(2): self.assertCountEqual( - Licence.get_autocomplete_queryset().values_list( - 'pk', flat=True - ), - [self.licence_1.pk, self.licence_2.pk] + Licence.get_autocomplete_queryset().values_list("pk", flat=True), + [self.licence_1.pk, self.licence_2.pk], ) def test_get_autocomplete_queryset_all_used(self): BaseObjectLicence.objects.create( - base_object=self.bo_asset, licence=self.licence_1, quantity=1, - ) - LicenceUser.objects.create( - user=self.user_1, licence=self.licence_1, quantity=2 + base_object=self.bo_asset, + licence=self.licence_1, + quantity=1, ) + LicenceUser.objects.create(user=self.user_1, licence=self.licence_1, quantity=2) with self.assertNumQueries(2): self.assertCountEqual( - Licence.get_autocomplete_queryset().values_list( - 'pk', flat=True - ), - [self.licence_2.pk] + Licence.get_autocomplete_queryset().values_list("pk", flat=True), + [self.licence_2.pk], ) @@ -71,34 +63,24 @@ def test_service_env_not_required(self): self.assertTrue(self.login_as_user()) licence = LicenceFactory() - url = reverse( - 'admin:licences_licence_change', - args=(licence.pk,) - ) + url = reverse("admin:licences_licence_change", args=(licence.pk,)) resp = self.client.get(url, follow=True) self.assertEqual(resp.status_code, 200) - form = resp.context['adminform'].form + form = resp.context["adminform"].form - self.assertIn('service_env', form.fields) - self.assertFalse( - form.fields['service_env'].required - ) + self.assertIn("service_env", form.fields) + self.assertFalse(form.fields["service_env"].required) def test_depreciation_rate_not_required(self): self.assertTrue(self.login_as_user()) licence = LicenceFactory() - url = reverse( - 'admin:licences_licence_change', - args=(licence.pk,) - ) + url = reverse("admin:licences_licence_change", args=(licence.pk,)) resp = self.client.get(url, follow=True) self.assertEqual(resp.status_code, 200) - form = resp.context['adminform'].form + form = resp.context["adminform"].form - self.assertIn('depreciation_rate', form.fields) - self.assertFalse( - form.fields['depreciation_rate'].required - ) + self.assertIn("depreciation_rate", form.fields) + self.assertFalse(form.fields["depreciation_rate"].required) diff --git a/src/ralph/networks/__init__.py b/src/ralph/networks/__init__.py index f076872d4b..53a81915c1 100644 --- a/src/ralph/networks/__init__.py +++ b/src/ralph/networks/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.networks.apps.Networks' +default_app_config = "ralph.networks.apps.Networks" diff --git a/src/ralph/networks/admin.py b/src/ralph/networks/admin.py index b477ab15a4..12cedfc639 100644 --- a/src/ralph/networks/admin.py +++ b/src/ralph/networks/admin.py @@ -18,44 +18,53 @@ ContainsIPAddressFilter, IPRangeFilter, NetworkClassFilter, - NetworkRangeFilter + NetworkRangeFilter, ) from ralph.networks.models.networks import ( DiscoveryQueue, IPAddress, Network, NetworkEnvironment, - NetworkKind + NetworkKind, ) @register(NetworkEnvironment) class NetworkEnvironmentAdmin(RalphAdmin): - list_display = ['name', 'data_center', 'use_hostname_counter'] + list_display = ["name", "data_center", "use_hostname_counter"] fieldsets = ( - (_('Basic info'), { - 'fields': [ - 'name', 'data_center', 'domain', 'remarks', - 'use_hostname_counter' - ], - }), - (_('Hostnames'), { - 'fields': [ - 'hostname_template_counter_length', - 'hostname_template_prefix', - 'hostname_template_postfix', - 'next_free_hostname', - ], - }), + ( + _("Basic info"), + { + "fields": [ + "name", + "data_center", + "domain", + "remarks", + "use_hostname_counter", + ], + }, + ), + ( + _("Hostnames"), + { + "fields": [ + "hostname_template_counter_length", + "hostname_template_prefix", + "hostname_template_postfix", + "next_free_hostname", + ], + }, + ), ) - readonly_fields = ['next_free_hostname'] - search_fields = ['name'] - list_filter = ['data_center'] + readonly_fields = ["next_free_hostname"] + search_fields = ["name"] + list_filter = ["data_center"] @register(NetworkKind) class NetworkKindAdmin(RalphAdmin): - search_fields = ['name'] + search_fields = ["name"] @register(DiscoveryQueue) @@ -65,23 +74,22 @@ class DiscoveryQueueAdmin(RalphAdmin): def ip_address_base_object_link(obj): if not obj.base_object: - return '–' + return "–" link = '{}'.format( - reverse('admin:view_on_site', args=( - obj.base_object.content_type_id, - obj.base_object.id - )), + reverse( + "admin:view_on_site", + args=(obj.base_object.content_type_id, obj.base_object.id), + ), escape(obj.base_object._str_with_type), ) return link class LinkedObjectTable(TableWithUrl): - def linked_object(self, item): return ip_address_base_object_link(item) - linked_object.title = _('Linked object') + linked_object.title = _("Linked object") class NetworkRalphChangeList(RalphChangeList): @@ -99,9 +107,9 @@ def get_queryset(self, request): """ queryset = super().get_queryset(request) any_params = ( - self.get_filters_params() or - self.params.get(SEARCH_VAR) or - self.params.get(ORDER_VAR) + self.get_filters_params() + or self.params.get(SEARCH_VAR) + or self.params.get(ORDER_VAR) ) if any_params: self.model_admin.mptt_indent_field = 10 @@ -112,188 +120,231 @@ def get_queryset(self, request): @register(Network) class NetworkAdmin(RalphMPTTAdmin): - ordering = ['min_ip', '-max_ip'] - change_form_template = 'admin/data_center/network/change_form.html' - search_fields = ['name', 'address', 'remarks', 'vlan'] + ordering = ["min_ip", "-max_ip"] + change_form_template = "admin/data_center/network/change_form.html" + search_fields = ["name", "address", "remarks", "vlan"] list_display = [ - 'name', 'address', 'kind', 'vlan', 'network_environment', - 'subnetworks_count', 'ipaddresses_count' + "name", + "address", + "kind", + "vlan", + "network_environment", + "subnetworks_count", + "ipaddresses_count", ] list_filter = [ - 'network_environment', 'kind', 'dhcp_broadcast', 'racks', - 'terminators', 'service_env', 'vlan', - ('parent', RelatedAutocompleteFieldListFilter), - ('min_ip', NetworkRangeFilter), ('address', NetworkClassFilter), - ('max_ip', ContainsIPAddressFilter) + "network_environment", + "kind", + "dhcp_broadcast", + "racks", + "terminators", + "service_env", + "vlan", + ("parent", RelatedAutocompleteFieldListFilter), + ("min_ip", NetworkRangeFilter), + ("address", NetworkClassFilter), + ("max_ip", ContainsIPAddressFilter), ] - list_select_related = ['kind', 'network_environment'] + list_select_related = ["kind", "network_environment"] raw_id_fields = [ - 'racks', 'gateway', 'terminators', 'service_env', 'dns_servers_group' + "racks", + "gateway", + "terminators", + "service_env", + "dns_servers_group", ] resource_class = resources.NetworkResource readonly_fields = [ - 'show_subnetworks', 'show_addresses', 'show_parent_networks', - 'show_first_free_ip', + "show_subnetworks", + "show_addresses", + "show_parent_networks", + "show_first_free_ip", ] add_message = _('Network added to {}') - change_message = _('Network reassigned from network {} to {}') # noqa + change_message = _( + 'Network reassigned from network {} to {}' + ) # noqa fieldsets = ( - (_('Basic info'), { - 'fields': [ - 'name', 'address', 'gateway', 'remarks', 'terminators', 'vlan', - 'racks', 'network_environment', 'dns_servers_group', 'kind', - 'service_env', 'dhcp_broadcast', 'reserved_from_beginning', - 'reserved_from_end', - ] - }), - (_('Relations'), { - 'fields': [ - 'show_first_free_ip', 'show_parent_networks', - 'show_subnetworks', 'show_addresses' - ] - }) + ( + _("Basic info"), + { + "fields": [ + "name", + "address", + "gateway", + "remarks", + "terminators", + "vlan", + "racks", + "network_environment", + "dns_servers_group", + "kind", + "service_env", + "dhcp_broadcast", + "reserved_from_beginning", + "reserved_from_end", + ] + }, + ), + ( + _("Relations"), + { + "fields": [ + "show_first_free_ip", + "show_parent_networks", + "show_subnetworks", + "show_addresses", + ] + }, + ), ) def get_changelist(self, request, **kwargs): return NetworkRalphChangeList - def changeform_view( - self, request, object_id=None, form_url='', extra_context=None - ): + def changeform_view(self, request, object_id=None, form_url="", extra_context=None): if not extra_context: extra_context = {} obj = self.get_object(request, object_id) if obj: - extra_context['next_free_ip'] = obj.get_first_free_ip() - return super().changeform_view( - request, object_id, form_url, extra_context - ) + extra_context["next_free_ip"] = obj.get_first_free_ip() + return super().changeform_view(request, object_id, form_url, extra_context) def address(self, obj): return obj.address - address.short_description = _('Network address') - address.admin_order_field = ['min_ip', '-max_ip'] + + address.short_description = _("Network address") + address.admin_order_field = ["min_ip", "-max_ip"] def subnetworks_count(self, obj): return obj.get_descendant_count() - subnetworks_count.short_description = _('Subnetworks count') - subnetworks_count.admin_order_field = 'subnetworks_count' + + subnetworks_count.short_description = _("Subnetworks count") + subnetworks_count.admin_order_field = "subnetworks_count" def ipaddresses_count(self, obj): return obj.ipaddress_count - ipaddresses_count.short_description = _('IPAddress count') - ipaddresses_count.admin_order_field = 'ipaddress_count' + + ipaddresses_count.short_description = _("IPAddress count") + ipaddresses_count.admin_order_field = "ipaddress_count" @mark_safe def show_parent_networks(self, network): if not network or not network.pk: - return '–' + return "–" nodes = network.get_ancestors(include_self=False) nodes_link = [] for node in nodes: - nodes_link.append('{}'.format( - node.get_absolute_url(), escape(node) - )) - return '
    '.join(nodes_link) - show_parent_networks.short_description = _('Parent networks') + nodes_link.append( + '{}'.format( + node.get_absolute_url(), escape(node) + ) + ) + return "
    ".join(nodes_link) + + show_parent_networks.short_description = _("Parent networks") @mark_safe def show_first_free_ip(self, network): if not network or not network.pk: - return '–' + return "–" free_ip = network.get_first_free_ip() - return str(free_ip) if free_ip else '–' - show_first_free_ip.short_description = _('First free IP') + return str(free_ip) if free_ip else "–" + + show_first_free_ip.short_description = _("First free IP") @mark_safe def show_subnetworks(self, network): if not network or not network.pk: - return '–' + return "–" return TableWithUrl( - network.get_subnetworks().order_by('min_ip'), - ['name', 'address'], - url_field='name' + network.get_subnetworks().order_by("min_ip"), + ["name", "address"], + url_field="name", ).render() - show_subnetworks.short_description = _('Subnetworks') + + show_subnetworks.short_description = _("Subnetworks") @mark_safe def show_addresses(self, network): if not network or not network.pk: - return '–' + return "–" return LinkedObjectTable( - IPAddress.objects.filter( - network=network - ).order_by( - 'number' - ).prefetch_related( + IPAddress.objects.filter(network=network) + .order_by("number") + .prefetch_related( Prefetch( - 'ethernet__base_object', - queryset=BaseObject.polymorphic_objects.all() + "ethernet__base_object", + queryset=BaseObject.polymorphic_objects.all(), ) ), - ['address', 'linked_object'], - url_field='address' + ["address", "linked_object"], + url_field="address", ).render() - show_addresses.short_description = _('Addresses') + + show_addresses.short_description = _("Addresses") def get_queryset(self, request): qs = super().get_queryset(request) # Getting subnetwork counts, used for column ordering # https://github.com/django-mptt/django-mptt/blob/master/mptt/models.py#L594 # noqa - qs = qs.annotate(ipaddress_count=Count('ips')).annotate( - subnetworks_count=( - CastToInteger(F('rght')) - CastToInteger(F('lft')) - ) + qs = qs.annotate(ipaddress_count=Count("ips")).annotate( + subnetworks_count=(CastToInteger(F("rght")) - CastToInteger(F("lft"))) ) return qs def get_paginator( - self, request, queryset, per_page, orphans=0, - allow_empty_first_page=True + self, request, queryset, per_page, orphans=0, allow_empty_first_page=True ): # Return all count found records because we want # display the tree mptt correctly for all networks. per_page = queryset.count() - return self.paginator( - queryset, per_page, orphans, allow_empty_first_page - ) + return self.paginator(queryset, per_page, orphans, allow_empty_first_page) @register(IPAddress) class IPAddressAdmin(ParentChangeMixin, RalphAdmin): - search_fields = ['address', 'hostname'] - ordering = ['number'] - list_filter = [ - 'hostname', 'is_public', 'is_management', ('address', IPRangeFilter) - ] + search_fields = ["address", "hostname"] + ordering = ["number"] + list_filter = ["hostname", "is_public", "is_management", ("address", IPRangeFilter)] list_display = [ - 'address', 'hostname', 'base_object_link', 'is_gateway', - 'is_public' + "address", + "hostname", + "base_object_link", + "is_gateway", + "is_public", ] - readonly_fields = ['get_network_path', 'is_public'] - raw_id_fields = ['ethernet'] + readonly_fields = ["get_network_path", "is_public"] + raw_id_fields = ["ethernet"] resource_class = resources.IPAddressResource fieldsets = ( - (_('Basic info'), { - 'fields': [ - 'address', 'get_network_path', 'status', 'ethernet' - ] - }), - (_('Additional info'), { - 'fields': [ - 'hostname', 'is_management', 'is_public', 'is_gateway', - 'dhcp_expose' - ] - }), + ( + _("Basic info"), + {"fields": ["address", "get_network_path", "status", "ethernet"]}, + ), + ( + _("Additional info"), + { + "fields": [ + "hostname", + "is_management", + "is_public", + "is_gateway", + "dhcp_expose", + ] + }, + ), ) add_message = _('IP added to {}') - change_message = _('IP reassigned from network {} to {}') # noqa + change_message = _( + 'IP reassigned from network {} to {}' + ) # noqa @mark_safe def get_network_path(self, obj): @@ -302,29 +353,38 @@ def get_network_path(self, obj): nodes = obj.network.get_ancestors(include_self=True) nodes_link = [] for node in nodes: - nodes_link.append('{}'.format( - node.get_absolute_url(), escape(node) - )) - return ' > '.join(nodes_link) - get_network_path.short_description = _('Network') + nodes_link.append( + '{}'.format( + node.get_absolute_url(), escape(node) + ) + ) + return " > ".join(nodes_link) + + get_network_path.short_description = _("Network") def get_queryset(self, request): # use Prefetch like select-related to get base_objects with custom # queryset (to get final model, not only BaseObject) - return super().get_queryset(request).prefetch_related(Prefetch( - 'ethernet__base_object', - queryset=BaseObject.polymorphic_objects.all()) + return ( + super() + .get_queryset(request) + .prefetch_related( + Prefetch( + "ethernet__base_object", + queryset=BaseObject.polymorphic_objects.all(), + ) + ) ) @mark_safe def ip_address(self, obj): - return '{}'.format( - obj.get_absolute_url(), escape(obj.address) - ) - ip_address.short_description = _('IP address') - ip_address.admin_order_field = 'number' + return '{}'.format(obj.get_absolute_url(), escape(obj.address)) + + ip_address.short_description = _("IP address") + ip_address.admin_order_field = "number" @mark_safe def base_object_link(self, obj): return ip_address_base_object_link(obj) - base_object_link.short_description = _('Linked object') + + base_object_link.short_description = _("Linked object") diff --git a/src/ralph/networks/api.py b/src/ralph/networks/api.py index 90d1760e7e..71372ee556 100644 --- a/src/ralph/networks/api.py +++ b/src/ralph/networks/api.py @@ -5,12 +5,7 @@ from ralph.api import RalphAPISerializer, RalphAPIViewSet, router from ralph.api.serializers import RalphAPISaveSerializer from ralph.assets.api.serializers import EthernetSerializer -from ralph.networks.models import ( - IPAddress, - Network, - NetworkEnvironment, - NetworkKind -) +from ralph.networks.models import IPAddress, Network, NetworkEnvironment, NetworkKind class NetworkEnvironmentSerializer(RalphAPISerializer): @@ -31,8 +26,14 @@ class NetworkSimpleSerializer(RalphAPISerializer): class Meta: model = Network fields = ( - 'id', 'url', 'name', 'remarks', 'vlan', 'dhcp_broadcast', 'parent', - 'network_environment' + "id", + "url", + "name", + "remarks", + "vlan", + "dhcp_broadcast", + "parent", + "network_environment", ) @@ -40,7 +41,7 @@ class NetworkSaveSerializer(RalphAPISerializer): class Meta: model = Network depth = 1 - exclude = ('min_ip', 'max_ip') + exclude = ("min_ip", "max_ip") class NetworkSerializer(RalphAPISerializer): @@ -57,7 +58,7 @@ class IPAddressSerializer(RalphAPISerializer): class Meta: model = IPAddress depth = 1 - exclude = ('number',) + exclude = ("number",) class IPAddressSaveSerializer(RalphAPISaveSerializer): @@ -70,13 +71,13 @@ def validate_dhcp_expose(self, value): Check if dhcp_expose value has changed from True to False. """ if ( - settings.DHCP_ENTRY_FORBID_CHANGE and - self.instance and - self.instance.dhcp_expose and - not value + settings.DHCP_ENTRY_FORBID_CHANGE + and self.instance + and self.instance.dhcp_expose + and not value ): raise ValidationError( - 'Cannot remove entry from DHCP. Use transition to do this.' + "Cannot remove entry from DHCP. Use transition to do this." ) return value @@ -86,19 +87,28 @@ class IPAddressViewSet(RalphAPIViewSet): serializer_class = IPAddressSerializer save_serializer_class = IPAddressSaveSerializer prefetch_related = [ - 'ethernet', 'ethernet__base_object', 'ethernet__base_object__tags', - 'network', + "ethernet", + "ethernet__base_object", + "ethernet__base_object__tags", + "network", ] filter_fields = [ - 'hostname', 'ethernet__base_object', 'network', 'network__address', - 'status', 'is_public', 'is_management', 'dhcp_expose', 'ethernet__mac', + "hostname", + "ethernet__base_object", + "network", + "network__address", + "status", + "is_public", + "is_management", + "dhcp_expose", + "ethernet__mac", ] def destroy(self, request, *args, **kwargs): instance = self.get_object() if instance and instance.dhcp_expose: raise ValidationError( - 'Could not delete IPAddress when it is exposed in DHCP' + "Could not delete IPAddress when it is exposed in DHCP" ) return super().destroy(request, *args, **kwargs) @@ -107,11 +117,11 @@ class NetworkViewSet(RalphAPIViewSet): queryset = Network.objects.all() serializer_class = NetworkSerializer save_serializer_class = NetworkSaveSerializer - select_related = ['network_environment', 'kind'] - prefetch_related = ['racks__accessories', 'terminators'] + select_related = ["network_environment", "kind"] + prefetch_related = ["racks__accessories", "terminators"] extended_filter_fields = { # workaround for custom field for address field defined in admin - 'address': ['address'], + "address": ["address"], } @@ -125,8 +135,8 @@ class NetworkKindViewSet(RalphAPIViewSet): serializer_class = NetworkKindSerializer -router.register(r'ipaddresses', IPAddressViewSet) -router.register(r'networks', NetworkViewSet) -router.register(r'network-environments', NetworkEnvironmentViewSet) -router.register(r'network-kinds', NetworkKindViewSet) +router.register(r"ipaddresses", IPAddressViewSet) +router.register(r"networks", NetworkViewSet) +router.register(r"network-environments", NetworkEnvironmentViewSet) +router.register(r"network-kinds", NetworkKindViewSet) urlpatterns = [] diff --git a/src/ralph/networks/api_simple.py b/src/ralph/networks/api_simple.py index 76e51ab85e..9aaf072bcc 100644 --- a/src/ralph/networks/api_simple.py +++ b/src/ralph/networks/api_simple.py @@ -5,6 +5,4 @@ class IPAddressSimpleSerializer(RalphAPISerializer): class Meta: model = IPAddress - fields = ( - 'id', 'address', 'hostname', 'dhcp_expose', 'is_management', 'url' - ) + fields = ("id", "address", "hostname", "dhcp_expose", "is_management", "url") diff --git a/src/ralph/networks/apps.py b/src/ralph/networks/apps.py index 5ed30e2330..94e6dc0f25 100644 --- a/src/ralph/networks/apps.py +++ b/src/ralph/networks/apps.py @@ -5,23 +5,18 @@ class Networks(RalphAppConfig): - name = 'ralph.networks' + name = "ralph.networks" def ready(self): if ( - not settings.ENABLE_DNSAAS_INTEGRATION or - not settings.DNSAAS_AUTO_UPDATE_HOST_DNS + not settings.ENABLE_DNSAAS_INTEGRATION + or not settings.DNSAAS_AUTO_UPDATE_HOST_DNS ): return - from ralph.networks.receivers import ( - delete_dns_record, - update_dns_record - ) - ip_model = self.get_model('IPAddress') - post_save.connect( - receiver=update_dns_record, - sender=ip_model - ) + from ralph.networks.receivers import delete_dns_record, update_dns_record + + ip_model = self.get_model("IPAddress") + post_save.connect(receiver=update_dns_record, sender=ip_model) pre_delete.connect( receiver=delete_dns_record, sender=ip_model, diff --git a/src/ralph/networks/fields.py b/src/ralph/networks/fields.py index cac8164f58..6745888d74 100644 --- a/src/ralph/networks/fields.py +++ b/src/ralph/networks/fields.py @@ -20,13 +20,11 @@ class IPNetwork(CharField): def __init__(self, *args, **kwargs): self.default_validators = [network_validator] - kwargs['max_length'] = MAX_NETWORK_ADDRESS_LENGTH + kwargs["max_length"] = MAX_NETWORK_ADDRESS_LENGTH super().__init__(*args, **kwargs) def db_type(self, connection): - return CharField( - max_length=MAX_NETWORK_ADDRESS_LENGTH - ).db_type(connection) + return CharField(max_length=MAX_NETWORK_ADDRESS_LENGTH).db_type(connection) def from_db_value(self, value, expression, connection, *_, **__): if value is None: diff --git a/src/ralph/networks/filters.py b/src/ralph/networks/filters.py index f0ddb28eb1..7bf601abaa 100644 --- a/src/ralph/networks/filters.py +++ b/src/ralph/networks/filters.py @@ -8,11 +8,13 @@ from ralph.admin.filters import ( ChoicesListFilter, SEARCH_OR_SEPARATORS_REGEX, - TextListFilter + TextListFilter, ) PRIVATE_NETWORK_CIDRS = [ - '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16", ] @@ -31,17 +33,14 @@ def get_private_network_filter(): def _add_incorrect_value_message(request, label): messages.warning( - request, _('Incorrect value in "%(field_name)s" filter') % { - 'field_name': label - } + request, _('Incorrect value in "%(field_name)s" filter') % {"field_name": label} ) class IPRangeFilter(TextListFilter): - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.title = _('IP range') + self.title = _("IP range") def queryset(self, request, queryset): if self.value(): @@ -57,13 +56,10 @@ def queryset(self, request, queryset): class NetworkRangeFilter(TextListFilter): - def __init__(self, field, request, params, model, model_admin, field_path): self.model_admin = model_admin - super().__init__( - field, request, params, model, model_admin, field_path - ) - self.title = _('Network range') + super().__init__(field, request, params, model, model_admin, field_path) + self.title = _("Network range") def queryset(self, request, queryset): if self.value(): @@ -81,30 +77,29 @@ def queryset(self, request, queryset): class NetworkClassFilter(ChoicesListFilter): _choices_list = [ - ('private', _('Private')), - ('public', _('Public')), + ("private", _("Private")), + ("public", _("Public")), ] def queryset(self, request, queryset): if not self.value(): return queryset - if self.value().lower() == 'private': + if self.value().lower() == "private": queryset = queryset.filter(PRIVATE_NETWORK_FILTER) - elif self.value().lower() == 'public': + elif self.value().lower() == "public": queryset = queryset.exclude(PRIVATE_NETWORK_FILTER) return queryset class ContainsIPAddressFilter(TextListFilter): - - title = _('Contains IP address') - parameter_name = 'contains_ip' + title = _("Contains IP address") + parameter_name = "contains_ip" def __init__(self, field, request, params, model, model_admin, field_path): super(ContainsIPAddressFilter, self).__init__( field, request, params, model, model_admin, field_path ) - self.title = _('Contains IP address') + self.title = _("Contains IP address") def queryset(self, request, queryset): if not self.value(): @@ -119,10 +114,7 @@ def queryset(self, request, queryset): _add_incorrect_value_message(request, self.title) raise IncorrectLookupParameters() - filter_query = filter_query | Q( - min_ip__lte=address, - max_ip__gte=address - ) + filter_query = filter_query | Q(min_ip__lte=address, max_ip__gte=address) queryset = queryset.filter(filter_query) diff --git a/src/ralph/networks/forms.py b/src/ralph/networks/forms.py index 7dd62f47f4..2d5368164e 100755 --- a/src/ralph/networks/forms.py +++ b/src/ralph/networks/forms.py @@ -10,7 +10,7 @@ from ralph.lib.field_validation.form_fields import CharFormFieldWithAutoStrip from ralph.networks.models import IPAddress -DHCP_EXPOSE_LOCKED_FIELDS = ['hostname', 'address', 'mac', 'dhcp_expose'] +DHCP_EXPOSE_LOCKED_FIELDS = ["hostname", "address", "mac", "dhcp_expose"] def validate_is_management(forms): @@ -20,18 +20,14 @@ def validate_is_management(forms): is_management = [] for form in forms: cleaned_data = form.cleaned_data - if ( - cleaned_data and - not cleaned_data.get('DELETE', False) - ): - is_management.append(cleaned_data.get('is_management')) + if cleaned_data and not cleaned_data.get("DELETE", False): + is_management.append(cleaned_data.get("is_management")) count_management_ip = is_management.count(True) if is_management and count_management_ip > 1: - raise ValidationError(( - 'Only one management IP address can be assigned ' - 'to this asset' - )) + raise ValidationError( + ("Only one management IP address can be assigned " "to this asset") + ) class EthernetLockDeleteForm(forms.ModelForm): @@ -39,7 +35,7 @@ class EthernetLockDeleteForm(forms.ModelForm): class Meta: model = Ethernet - fields = ['mac', 'model_name', 'label', 'speed'] + fields = ["mac", "model_name", "label", "speed"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -61,8 +57,8 @@ def __init__(self, *args, **kwargs): pass else: if isinstance(field, forms.BooleanField): - field.widget.attrs['disabled'] = True - field.widget.attrs['readonly'] = True + field.widget.attrs["disabled"] = True + field.widget.attrs["readonly"] = True @property def _dhcp_expose_should_lock_fields(self): @@ -70,11 +66,11 @@ def _dhcp_expose_should_lock_fields(self): Return True if row should be locked for changes if it's exposed in DHCP. """ return ( - settings.DHCP_ENTRY_FORBID_CHANGE and - self.instance and - self.instance.pk and - self.ip and - self.ip.dhcp_expose + settings.DHCP_ENTRY_FORBID_CHANGE + and self.instance + and self.instance.pk + and self.ip + and self.ip.dhcp_expose ) @@ -98,19 +94,20 @@ class SimpleNetworkForm(EthernetLockDeleteForm): transition changing `dhcp_expose` field (to False) - then row could be modified/deleted. """ - hostname = CharFormFieldWithAutoStrip(label='Hostname', required=False) + + hostname = CharFormFieldWithAutoStrip(label="Hostname", required=False) address = forms.GenericIPAddressField( - label='IP address', - required=False, - protocol='IPv4' + label="IP address", required=False, protocol="IPv4" ) - ip_fields = ['hostname', 'address'] + ip_fields = ["hostname", "address"] class Meta: model = Ethernet fields = [ - 'hostname', 'address', 'mac', + "hostname", + "address", + "mac", ] def _validate_ip_uniquness(self, address): @@ -122,25 +119,25 @@ def _validate_ip_uniquness(self, address): qs = qs.exclude(pk=self.ip.pk) if qs.exists(): raise ValidationError( - _('Address %(ip)s already exist.'), - params={'ip': address}, + _("Address %(ip)s already exist."), + params={"ip": address}, ) def _validate_hostame_uniqueness_in_dc(self): - address = self.cleaned_data['address'] - new_hostname = self.cleaned_data['hostname'] - if not self.ip or self.ip.address != address: - ip = IPAddress(address=address, hostname=new_hostname) - else: - ip = self.ip - ip.validate_hostname_uniqueness_in_dc(new_hostname) + address = self.cleaned_data["address"] + new_hostname = self.cleaned_data["hostname"] + if not self.ip or self.ip.address != address: + ip = IPAddress(address=address, hostname=new_hostname) + else: + ip = self.ip + ip.validate_hostname_uniqueness_in_dc(new_hostname) def clean_address(self): if self._dhcp_expose_should_lock_fields: # if address is locked, just return current address address = self.ip.address else: - address = self.cleaned_data['address'] + address = self.cleaned_data["address"] self._validate_ip_uniquness(address) return address @@ -148,13 +145,13 @@ def clean_mac(self): if self._dhcp_expose_should_lock_fields: # if mac is locked, just return current mac return self.instance.mac - return self.cleaned_data['mac'] + return self.cleaned_data["mac"] def clean_hostname(self): if self._dhcp_expose_should_lock_fields: # if mac is locked, just return current hostname return self.ip.hostname - return self.cleaned_data['hostname'] + return self.cleaned_data["hostname"] def clean_dhcp_expose(self): """ @@ -164,19 +161,19 @@ def clean_dhcp_expose(self): if self._dhcp_expose_should_lock_fields: # if dhcp expose is locked, just return current address return self.ip.dhcp_expose - dhcp_expose = self.cleaned_data['dhcp_expose'] + dhcp_expose = self.cleaned_data["dhcp_expose"] if dhcp_expose: - if not self.cleaned_data.get('address'): + if not self.cleaned_data.get("address"): raise ValidationError( - _('Cannot expose in DHCP without IP address'), + _("Cannot expose in DHCP without IP address"), ) - if not self.cleaned_data.get('hostname'): + if not self.cleaned_data.get("hostname"): raise ValidationError( - _('Cannot expose in DHCP without hostname'), + _("Cannot expose in DHCP without hostname"), ) - if not self.cleaned_data.get('mac'): + if not self.cleaned_data.get("mac"): raise ValidationError( - _('Cannot expose in DHCP without MAC address'), + _("Cannot expose in DHCP without MAC address"), ) self._validate_hostame_uniqueness_in_dc() return dhcp_expose @@ -185,25 +182,23 @@ def _validate_mac_address(self): """ Validate if any of mac and address are filled. """ - fields = ['mac', 'address'] + fields = ["mac", "address"] if not any([self.cleaned_data.get(field) for field in fields]): - raise ValidationError(_('At least one of {} is required'.format( - ', '.join(fields) - ))) + raise ValidationError( + _("At least one of {} is required".format(", ".join(fields))) + ) def _validate_ip_fields(self): """ If adddress is not filled and any other ip field is filled, raise error. """ - ip_fields_without_address = [ - f for f in self.ip_fields if f != 'address' - ] - if not self.cleaned_data.get('address') and any([ - self.cleaned_data.get(f) for f in ip_fields_without_address - ]): + ip_fields_without_address = [f for f in self.ip_fields if f != "address"] + if not self.cleaned_data.get("address") and any( + [self.cleaned_data.get(f) for f in ip_fields_without_address] + ): raise ValidationError( - 'Address is required when one of {} is filled'.format( - ', '.join(ip_fields_without_address) + "Address is required when one of {} is filled".format( + ", ".join(ip_fields_without_address) ) ) @@ -222,29 +217,26 @@ def save(self, commit=True): if self.ip: self.ip.__dict__.update(ip_values) self.ip.save() - elif ip_values['address']: + elif ip_values["address"]: # save IP only if there is address passed in the form IPAddress.objects.create(ethernet=obj, **ip_values) return obj class SimpleNetworkWithManagementIPForm(SimpleNetworkForm): - is_management = forms.BooleanField(label='Is management', required=False) + is_management = forms.BooleanField(label="Is management", required=False) - ip_fields = ['hostname', 'address', 'is_management'] + ip_fields = ["hostname", "address", "is_management"] class NetworkForm(SimpleNetworkWithManagementIPForm): - dhcp_expose = forms.BooleanField(label=_('Expose in DHCP'), required=False) + dhcp_expose = forms.BooleanField(label=_("Expose in DHCP"), required=False) - ip_fields = ['hostname', 'address', 'is_management', 'dhcp_expose'] + ip_fields = ["hostname", "address", "is_management", "dhcp_expose"] class Meta: model = Ethernet - fields = [ - 'hostname', 'address', 'mac', 'is_management', 'label', - 'dhcp_expose' - ] + fields = ["hostname", "address", "mac", "is_management", "label", "dhcp_expose"] class NetworkInlineFormset(BaseInlineFormSet): @@ -254,7 +246,7 @@ def add_fields(self, form, index): # many other places in Django code depends on DELETE field # so instead of deleting it here, we're just hiding it and validate # if it's not used - form.fields[DELETION_FIELD_NAME].widget.attrs['hidden'] = True + form.fields[DELETION_FIELD_NAME].widget.attrs["hidden"] = True def clean(self): result = super().clean() @@ -267,14 +259,9 @@ def _validate_can_delete(self): Forbid deletion of rows with 'dhcp_entry' enabled. """ for form in self.forms: - if not hasattr(form, 'cleaned_data'): + if not hasattr(form, "cleaned_data"): continue data = form.cleaned_data - if ( - data.get('DELETE') and - form._dhcp_expose_should_lock_fields - ): - raise ValidationError( - "Cannot delete entry if its exposed in DHCP" - ) + if data.get("DELETE") and form._dhcp_expose_should_lock_fields: + raise ValidationError("Cannot delete entry if its exposed in DHCP") diff --git a/src/ralph/networks/migrations/0001_initial.py b/src/ralph/networks/migrations/0001_initial.py index f6dd5c571a..b86e29d64b 100644 --- a/src/ralph/networks/migrations/0001_initial.py +++ b/src/ralph/networks/migrations/0001_initial.py @@ -11,149 +11,422 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0013_auto_20160606_1438'), - ('dhcp', '__first__'), - ('assets', '0012_auto_20160606_1409'), + ("data_center", "0013_auto_20160606_1438"), + ("dhcp", "__first__"), + ("assets", "0012_auto_20160606_1409"), ] state_operations = [ migrations.CreateModel( - name='DiscoveryQueue', + name="DiscoveryQueue", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), ], options={ - 'verbose_name': 'discovery queue', - 'verbose_name_plural': 'discovery queues', - 'ordering': ('name',), + "verbose_name": "discovery queue", + "verbose_name_plural": "discovery queues", + "ordering": ("name",), }, ), migrations.CreateModel( - name='IPAddress', + name="IPAddress", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), - ('last_seen', models.DateTimeField(verbose_name='last seen', auto_now_add=True)), - ('address', models.GenericIPAddressField(default=None, null=True, help_text='Presented as string.', verbose_name='IP address', unique=True)), - ('hostname', models.CharField(default=None, null=True, verbose_name='Hostname', blank=True, max_length=255)), - ('number', models.DecimalField(default=None, help_text='Presented as int.', verbose_name='IP address', max_digits=39, editable=False, decimal_places=0, unique=True)), - ('is_management', models.BooleanField(default=False, verbose_name='This is a management address')), - ('is_public', models.BooleanField(default=False, editable=False, verbose_name='This is a public address')), - ('is_gateway', models.BooleanField(default=False, editable=False, verbose_name='This is a gateway address')), - ('status', models.PositiveSmallIntegerField(default=1, choices=[(1, 'DHCP (used)'), (2, 'reserved')])), - ('base_object', models.ForeignKey(default=None, null=True, to='assets.BaseObject', verbose_name='Base object', blank=True, on_delete=django.db.models.deletion.SET_NULL)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), + ( + "last_seen", + models.DateTimeField(verbose_name="last seen", auto_now_add=True), + ), + ( + "address", + models.GenericIPAddressField( + default=None, + null=True, + help_text="Presented as string.", + verbose_name="IP address", + unique=True, + ), + ), + ( + "hostname", + models.CharField( + default=None, + null=True, + verbose_name="Hostname", + blank=True, + max_length=255, + ), + ), + ( + "number", + models.DecimalField( + default=None, + help_text="Presented as int.", + verbose_name="IP address", + max_digits=39, + editable=False, + decimal_places=0, + unique=True, + ), + ), + ( + "is_management", + models.BooleanField( + default=False, verbose_name="This is a management address" + ), + ), + ( + "is_public", + models.BooleanField( + default=False, + editable=False, + verbose_name="This is a public address", + ), + ), + ( + "is_gateway", + models.BooleanField( + default=False, + editable=False, + verbose_name="This is a gateway address", + ), + ), + ( + "status", + models.PositiveSmallIntegerField( + default=1, choices=[(1, "DHCP (used)"), (2, "reserved")] + ), + ), + ( + "base_object", + models.ForeignKey( + default=None, + null=True, + to="assets.BaseObject", + verbose_name="Base object", + blank=True, + on_delete=django.db.models.deletion.SET_NULL, + ), + ), ], options={ - 'verbose_name_plural': 'IP addresses', - 'verbose_name': 'IP address', + "verbose_name_plural": "IP addresses", + "verbose_name": "IP address", }, bases=(ralph.networks.models.networks.NetworkMixin, models.Model), ), migrations.CreateModel( - name='Network', + name="Network", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), - ('address', ralph.networks.fields.IPNetwork(help_text='Presented as string (e.g. 192.168.0.0/24)', verbose_name='network address')), - ('remarks', models.TextField(default='', help_text='Additional information.', verbose_name='remarks', blank=True)), - ('vlan', models.PositiveIntegerField(default=None, null=True, verbose_name='VLAN number', blank=True)), - ('min_ip', models.DecimalField(default=None, null=True, editable=False, verbose_name='smallest IP number', blank=True, max_digits=39, decimal_places=0)), - ('max_ip', models.DecimalField(default=None, null=True, editable=False, verbose_name='largest IP number', blank=True, max_digits=39, decimal_places=0)), - ('dhcp_broadcast', models.BooleanField(default=False, db_index=True, verbose_name='Broadcast in DHCP configuration')), - ('lft', models.PositiveIntegerField(db_index=True, editable=False)), - ('rght', models.PositiveIntegerField(db_index=True, editable=False)), - ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), - ('level', models.PositiveIntegerField(db_index=True, editable=False)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), + ( + "address", + ralph.networks.fields.IPNetwork( + help_text="Presented as string (e.g. 192.168.0.0/24)", + verbose_name="network address", + ), + ), + ( + "remarks", + models.TextField( + default="", + help_text="Additional information.", + verbose_name="remarks", + blank=True, + ), + ), + ( + "vlan", + models.PositiveIntegerField( + default=None, null=True, verbose_name="VLAN number", blank=True + ), + ), + ( + "min_ip", + models.DecimalField( + default=None, + null=True, + editable=False, + verbose_name="smallest IP number", + blank=True, + max_digits=39, + decimal_places=0, + ), + ), + ( + "max_ip", + models.DecimalField( + default=None, + null=True, + editable=False, + verbose_name="largest IP number", + blank=True, + max_digits=39, + decimal_places=0, + ), + ), + ( + "dhcp_broadcast", + models.BooleanField( + default=False, + db_index=True, + verbose_name="Broadcast in DHCP configuration", + ), + ), + ("lft", models.PositiveIntegerField(db_index=True, editable=False)), + ("rght", models.PositiveIntegerField(db_index=True, editable=False)), + ("tree_id", models.PositiveIntegerField(db_index=True, editable=False)), + ("level", models.PositiveIntegerField(db_index=True, editable=False)), ], options={ - 'verbose_name_plural': 'networks', - 'verbose_name': 'network', + "verbose_name_plural": "networks", + "verbose_name": "network", }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, ralph.networks.models.networks.NetworkMixin, models.Model), + bases=( + ralph.lib.mixins.models.AdminAbsoluteUrlMixin, + ralph.networks.models.networks.NetworkMixin, + models.Model, + ), ), migrations.CreateModel( - name='NetworkEnvironment', + name="NetworkEnvironment", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), - ('hosts_naming_template', models.CharField(help_text='E.g. h<200,299>.dc|h<400,499>.dc will produce: h200.dc h201.dc ... h299.dc h400.dc h401.dc', verbose_name='hosts naming template', max_length=30)), - ('next_server', models.CharField(default='', help_text='The address for a TFTP server for DHCP.', verbose_name='next server', blank=True, max_length=32)), - ('domain', models.CharField(null=True, verbose_name='domain', blank=True, max_length=255)), - ('remarks', models.TextField(null=True, help_text='Additional information.', verbose_name='remarks', blank=True)), - ('data_center', models.ForeignKey(to='data_center.DataCenter', verbose_name='data center', on_delete=django.db.models.deletion.CASCADE)), - ('queue', models.ForeignKey(null=True, to='networks.DiscoveryQueue', verbose_name='discovery queue', blank=True, on_delete=django.db.models.deletion.SET_NULL)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), + ( + "hosts_naming_template", + models.CharField( + help_text="E.g. h<200,299>.dc|h<400,499>.dc will produce: h200.dc h201.dc ... h299.dc h400.dc h401.dc", + verbose_name="hosts naming template", + max_length=30, + ), + ), + ( + "next_server", + models.CharField( + default="", + help_text="The address for a TFTP server for DHCP.", + verbose_name="next server", + blank=True, + max_length=32, + ), + ), + ( + "domain", + models.CharField( + null=True, verbose_name="domain", blank=True, max_length=255 + ), + ), + ( + "remarks", + models.TextField( + null=True, + help_text="Additional information.", + verbose_name="remarks", + blank=True, + ), + ), + ( + "data_center", + models.ForeignKey( + to="data_center.DataCenter", + verbose_name="data center", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "queue", + models.ForeignKey( + null=True, + to="networks.DiscoveryQueue", + verbose_name="discovery queue", + blank=True, + on_delete=django.db.models.deletion.SET_NULL, + ), + ), ], options={ - 'ordering': ('name',), + "ordering": ("name",), }, ), migrations.CreateModel( - name='NetworkKind', + name="NetworkKind", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), ], options={ - 'verbose_name': 'network kind', - 'verbose_name_plural': 'network kinds', - 'ordering': ('name',), + "verbose_name": "network kind", + "verbose_name_plural": "network kinds", + "ordering": ("name",), }, ), migrations.CreateModel( - name='NetworkTerminator', + name="NetworkTerminator", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), ], options={ - 'verbose_name': 'network terminator', - 'verbose_name_plural': 'network terminators', - 'ordering': ('name',), + "verbose_name": "network terminator", + "verbose_name_plural": "network terminators", + "ordering": ("name",), }, ), migrations.AddField( - model_name='network', - name='kind', - field=models.ForeignKey(default=None, null=True, to='networks.NetworkKind', verbose_name='network kind', blank=True, on_delete=django.db.models.deletion.SET_NULL), + model_name="network", + name="kind", + field=models.ForeignKey( + default=None, + null=True, + to="networks.NetworkKind", + verbose_name="network kind", + blank=True, + on_delete=django.db.models.deletion.SET_NULL, + ), ), migrations.AddField( - model_name='network', - name='network_environment', - field=models.ForeignKey(null=True, to='networks.NetworkEnvironment', verbose_name='environment', blank=True, on_delete=django.db.models.deletion.SET_NULL), + model_name="network", + name="network_environment", + field=models.ForeignKey( + null=True, + to="networks.NetworkEnvironment", + verbose_name="environment", + blank=True, + on_delete=django.db.models.deletion.SET_NULL, + ), ), migrations.AddField( - model_name='network', - name='parent', - field=mptt.fields.TreeForeignKey(null=True, editable=False, blank=True, to='networks.Network', related_name='children', on_delete=django.db.models.deletion.CASCADE), + model_name="network", + name="parent", + field=mptt.fields.TreeForeignKey( + null=True, + editable=False, + blank=True, + to="networks.Network", + related_name="children", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='network', - name='racks', - field=models.ManyToManyField(to='data_center.Rack', verbose_name='racks', blank=True), + model_name="network", + name="racks", + field=models.ManyToManyField( + to="data_center.Rack", verbose_name="racks", blank=True + ), ), migrations.AddField( - model_name='network', - name='terminators', - field=models.ManyToManyField(to='networks.NetworkTerminator', verbose_name='network terminators', blank=True), + model_name="network", + name="terminators", + field=models.ManyToManyField( + to="networks.NetworkTerminator", + verbose_name="network terminators", + blank=True, + ), ), migrations.AddField( - model_name='ipaddress', - name='network', - field=models.ForeignKey(default=None, null=True, editable=False, on_delete=django.db.models.deletion.SET_NULL, to='networks.Network', related_name='ips'), + model_name="ipaddress", + name="network", + field=models.ForeignKey( + default=None, + null=True, + editable=False, + on_delete=django.db.models.deletion.SET_NULL, + to="networks.Network", + related_name="ips", + ), ), migrations.AlterUniqueTogether( - name='network', - unique_together=set([('min_ip', 'max_ip')]), + name="network", + unique_together=set([("min_ip", "max_ip")]), ), ] operations = [ migrations.SeparateDatabaseAndState(state_operations=state_operations) ] - diff --git a/src/ralph/networks/migrations/0002_add_ethernet_field.py b/src/ralph/networks/migrations/0002_add_ethernet_field.py index 688f756fd3..f63b86b680 100644 --- a/src/ralph/networks/migrations/0002_add_ethernet_field.py +++ b/src/ralph/networks/migrations/0002_add_ethernet_field.py @@ -6,15 +6,20 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0001_initial'), + ("networks", "0001_initial"), ] operations = [ migrations.AddField( - model_name='ipaddress', - name='ethernet', - field=models.OneToOneField(to='assets.Ethernet', default=None, blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="ipaddress", + name="ethernet", + field=models.OneToOneField( + to="assets.Ethernet", + default=None, + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/networks/migrations/0003_custom_link_ips_to_eth.py b/src/ralph/networks/migrations/0003_custom_link_ips_to_eth.py index 16457ad58a..a611528ded 100644 --- a/src/ralph/networks/migrations/0003_custom_link_ips_to_eth.py +++ b/src/ralph/networks/migrations/0003_custom_link_ips_to_eth.py @@ -1,16 +1,14 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations def move_from_base_object_to_ethernet(apps, schema_editor): - IPAddress = apps.get_model('networks', 'IPAddress') - Ethernet = apps.get_model('assets', 'Ethernet') + IPAddress = apps.get_model("networks", "IPAddress") + Ethernet = apps.get_model("assets", "Ethernet") - for ip in IPAddress.objects.filter( - base_object__isnull=False - ): + for ip in IPAddress.objects.filter(base_object__isnull=False): if not ip.ethernet: ip.ethernet = Ethernet.objects.create(base_object=ip.base_object) else: @@ -20,7 +18,7 @@ def move_from_base_object_to_ethernet(apps, schema_editor): def move_from_ethernet_to_base_object(apps, schema_editor): - Ethernet = apps.get_model('assets', 'Ethernet') + Ethernet = apps.get_model("assets", "Ethernet") for eth in Ethernet.objects.filter( ipaddress__isnull=False, ): @@ -29,15 +27,14 @@ def move_from_ethernet_to_base_object(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('networks', '0002_add_ethernet_field'), - ('data_center', '0014_custom_move_managment_to_networks'), + ("networks", "0002_add_ethernet_field"), + ("data_center", "0014_custom_move_managment_to_networks"), ] operations = [ migrations.RunPython( move_from_base_object_to_ethernet, - reverse_code=move_from_ethernet_to_base_object + reverse_code=move_from_ethernet_to_base_object, ) ] diff --git a/src/ralph/networks/migrations/0004_auto_20160606_1512.py b/src/ralph/networks/migrations/0004_auto_20160606_1512.py index 195bef2a7b..63b383aa30 100644 --- a/src/ralph/networks/migrations/0004_auto_20160606_1512.py +++ b/src/ralph/networks/migrations/0004_auto_20160606_1512.py @@ -8,138 +8,211 @@ class Migration(migrations.Migration): - dependencies = [ - ('dhcp', '0002_dhcpentry'), - ('assets', '0012_auto_20160606_1409'), - ('networks', '0003_custom_link_ips_to_eth'), + ("dhcp", "0002_dhcpentry"), + ("assets", "0012_auto_20160606_1409"), + ("networks", "0003_custom_link_ips_to_eth"), ] operations = [ migrations.RemoveField( - model_name='ipaddress', - name='base_object', + model_name="ipaddress", + name="base_object", ), migrations.RemoveField( - model_name='networkenvironment', - name='hosts_naming_template', + model_name="networkenvironment", + name="hosts_naming_template", ), migrations.RemoveField( - model_name='networkenvironment', - name='next_server', + model_name="networkenvironment", + name="next_server", ), migrations.AddField( - model_name='ipaddress', - name='dhcp_expose', - field=models.BooleanField(default=False, verbose_name='Expose in DHCP'), + model_name="ipaddress", + name="dhcp_expose", + field=models.BooleanField(default=False, verbose_name="Expose in DHCP"), ), migrations.AddField( - model_name='network', - name='dns_servers', - field=models.ManyToManyField(to='dhcp.DNSServer', blank=True, verbose_name='DNS servers'), + model_name="network", + name="dns_servers", + field=models.ManyToManyField( + to="dhcp.DNSServer", blank=True, verbose_name="DNS servers" + ), ), migrations.AddField( - model_name='network', - name='service_env', - field=models.ForeignKey(to='assets.ServiceEnvironment', related_name='networks', default=None, blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="network", + name="service_env", + field=models.ForeignKey( + to="assets.ServiceEnvironment", + related_name="networks", + default=None, + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='networkenvironment', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created', default=datetime.datetime(2016, 6, 6, 15, 11, 14, 733956)), + model_name="networkenvironment", + name="created", + field=models.DateTimeField( + auto_now_add=True, + verbose_name="date created", + default=datetime.datetime(2016, 6, 6, 15, 11, 14, 733956), + ), preserve_default=False, ), migrations.AddField( - model_name='networkenvironment', - name='hostname_template_counter_length', - field=models.PositiveIntegerField(default=4, verbose_name='hostname template counter length'), + model_name="networkenvironment", + name="hostname_template_counter_length", + field=models.PositiveIntegerField( + default=4, verbose_name="hostname template counter length" + ), ), migrations.AddField( - model_name='networkenvironment', - name='hostname_template_postfix', - field=models.CharField(default='', max_length=30, verbose_name='hostname template postfix', help_text='This value will be used as a postfix when generating new hostname in this network environment. For example, when prefix is "s1", postfix is ".mydc.net" and counter length is 4, following hostnames will be generated: s10000.mydc.net, s10001.mydc.net, .., s19999.mydc.net.'), + model_name="networkenvironment", + name="hostname_template_postfix", + field=models.CharField( + default="", + max_length=30, + verbose_name="hostname template postfix", + help_text='This value will be used as a postfix when generating new hostname in this network environment. For example, when prefix is "s1", postfix is ".mydc.net" and counter length is 4, following hostnames will be generated: s10000.mydc.net, s10001.mydc.net, .., s19999.mydc.net.', + ), preserve_default=False, ), migrations.AddField( - model_name='networkenvironment', - name='hostname_template_prefix', - field=models.CharField(default='', max_length=30, verbose_name='hostname template prefix'), + model_name="networkenvironment", + name="hostname_template_prefix", + field=models.CharField( + default="", max_length=30, verbose_name="hostname template prefix" + ), preserve_default=False, ), migrations.AddField( - model_name='networkenvironment', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified', default=datetime.datetime(2016, 6, 6, 15, 11, 34, 653279)), + model_name="networkenvironment", + name="modified", + field=models.DateTimeField( + auto_now=True, + verbose_name="last modified", + default=datetime.datetime(2016, 6, 6, 15, 11, 34, 653279), + ), preserve_default=False, ), migrations.AlterField( - model_name='ipaddress', - name='address', - field=models.GenericIPAddressField(default='0.0.0.0', unique=True, verbose_name='IP address', help_text='Presented as string.'), + model_name="ipaddress", + name="address", + field=models.GenericIPAddressField( + default="0.0.0.0", + unique=True, + verbose_name="IP address", + help_text="Presented as string.", + ), preserve_default=False, ), migrations.AlterField( - model_name='ipaddress', - name='hostname', - field=ralph.lib.mixins.fields.NullableCharField(default=None, max_length=255, blank=True, verbose_name='Hostname', null=True), + model_name="ipaddress", + name="hostname", + field=ralph.lib.mixins.fields.NullableCharField( + default=None, + max_length=255, + blank=True, + verbose_name="Hostname", + null=True, + ), ), migrations.AlterField( - model_name='ipaddress', - name='is_gateway', - field=models.BooleanField(default=False, verbose_name='Is gateway'), + model_name="ipaddress", + name="is_gateway", + field=models.BooleanField(default=False, verbose_name="Is gateway"), ), migrations.AlterField( - model_name='ipaddress', - name='is_management', - field=models.BooleanField(default=False, verbose_name='Is management address'), + model_name="ipaddress", + name="is_management", + field=models.BooleanField( + default=False, verbose_name="Is management address" + ), ), migrations.AlterField( - model_name='ipaddress', - name='is_public', - field=models.BooleanField(editable=False, verbose_name='Is public', default=False), + model_name="ipaddress", + name="is_public", + field=models.BooleanField( + editable=False, verbose_name="Is public", default=False + ), ), migrations.AlterField( - model_name='ipaddress', - name='status', - field=models.PositiveSmallIntegerField(default=1, choices=[(1, 'used (fixed address in DHCP)'), (2, 'reserved')]), + model_name="ipaddress", + name="status", + field=models.PositiveSmallIntegerField( + default=1, + choices=[(1, "used (fixed address in DHCP)"), (2, "reserved")], + ), ), migrations.AlterField( - model_name='network', - name='dhcp_broadcast', - field=models.BooleanField(default=True, db_index=True, verbose_name='Broadcast in DHCP configuration'), + model_name="network", + name="dhcp_broadcast", + field=models.BooleanField( + default=True, + db_index=True, + verbose_name="Broadcast in DHCP configuration", + ), ), migrations.AlterField( - model_name='network', - name='kind', - field=models.ForeignKey(verbose_name='network kind', to='networks.NetworkKind', on_delete=django.db.models.deletion.SET_NULL, blank=True, null=True), + model_name="network", + name="kind", + field=models.ForeignKey( + verbose_name="network kind", + to="networks.NetworkKind", + on_delete=django.db.models.deletion.SET_NULL, + blank=True, + null=True, + ), ), migrations.AlterField( - model_name='network', - name='max_ip', - field=models.DecimalField(editable=False, decimal_places=0, max_digits=39, verbose_name='largest IP number', default=0), + model_name="network", + name="max_ip", + field=models.DecimalField( + editable=False, + decimal_places=0, + max_digits=39, + verbose_name="largest IP number", + default=0, + ), preserve_default=False, ), migrations.AlterField( - model_name='network', - name='min_ip', - field=models.DecimalField(editable=False, decimal_places=0, max_digits=39, verbose_name='smallest IP number', default=0), + model_name="network", + name="min_ip", + field=models.DecimalField( + editable=False, + decimal_places=0, + max_digits=39, + verbose_name="smallest IP number", + default=0, + ), preserve_default=False, ), migrations.RemoveField( - model_name='network', - name='terminators', + model_name="network", + name="terminators", ), migrations.DeleteModel( - name='NetworkTerminator', + name="NetworkTerminator", ), migrations.AddField( - model_name='network', - name='terminators', - field=models.ManyToManyField(to='assets.BaseObject', verbose_name='network terminators', blank=True), + model_name="network", + name="terminators", + field=models.ManyToManyField( + to="assets.BaseObject", verbose_name="network terminators", blank=True + ), ), migrations.AlterField( - model_name='networkenvironment', - name='domain', - field=ralph.lib.mixins.fields.NullableCharField(null=True, max_length=255, blank=True, verbose_name='domain', help_text='Used in DHCP configuration.'), + model_name="networkenvironment", + name="domain", + field=ralph.lib.mixins.fields.NullableCharField( + null=True, + max_length=255, + blank=True, + verbose_name="domain", + help_text="Used in DHCP configuration.", + ), ), ] diff --git a/src/ralph/networks/migrations/0005_network_gateway.py b/src/ralph/networks/migrations/0005_network_gateway.py index 322bcf7268..e6cdf94f7d 100644 --- a/src/ralph/networks/migrations/0005_network_gateway.py +++ b/src/ralph/networks/migrations/0005_network_gateway.py @@ -6,15 +6,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0004_auto_20160606_1512'), + ("networks", "0004_auto_20160606_1512"), ] operations = [ migrations.AddField( - model_name='network', - name='gateway', - field=models.ForeignKey(to='networks.IPAddress', null=True, verbose_name='Gateway address', blank=True, related_name='gateway_network', on_delete=django.db.models.deletion.CASCADE), + model_name="network", + name="gateway", + field=models.ForeignKey( + to="networks.IPAddress", + null=True, + verbose_name="Gateway address", + blank=True, + related_name="gateway_network", + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/networks/migrations/0006_networkenvironment_use_hostname_counter.py b/src/ralph/networks/migrations/0006_networkenvironment_use_hostname_counter.py index 9d050ded98..750be27d5e 100644 --- a/src/ralph/networks/migrations/0006_networkenvironment_use_hostname_counter.py +++ b/src/ralph/networks/migrations/0006_networkenvironment_use_hostname_counter.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0005_network_gateway'), + ("networks", "0005_network_gateway"), ] operations = [ migrations.AddField( - model_name='networkenvironment', - name='use_hostname_counter', - field=models.BooleanField(default=True, help_text='If set to false hostname based on already added hostnames.'), + model_name="networkenvironment", + name="use_hostname_counter", + field=models.BooleanField( + default=True, + help_text="If set to false hostname based on already added hostnames.", + ), ), ] diff --git a/src/ralph/networks/migrations/0007_auto_20160804_1409.py b/src/ralph/networks/migrations/0007_auto_20160804_1409.py index dcd6b2161f..08a81780d7 100644 --- a/src/ralph/networks/migrations/0007_auto_20160804_1409.py +++ b/src/ralph/networks/migrations/0007_auto_20160804_1409.py @@ -1,20 +1,24 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.networks.fields class Migration(migrations.Migration): - dependencies = [ - ('networks', '0006_networkenvironment_use_hostname_counter'), + ("networks", "0006_networkenvironment_use_hostname_counter"), ] operations = [ migrations.AlterField( - model_name='network', - name='address', - field=ralph.networks.fields.IPNetwork(verbose_name='network address', unique=True, help_text='Presented as string (e.g. 192.168.0.0/24)', max_length=44), + model_name="network", + name="address", + field=ralph.networks.fields.IPNetwork( + verbose_name="network address", + unique=True, + help_text="Presented as string (e.g. 192.168.0.0/24)", + max_length=44, + ), ), ] diff --git a/src/ralph/networks/migrations/0008_auto_20160808_0719.py b/src/ralph/networks/migrations/0008_auto_20160808_0719.py index 47433a9d24..1e042490c3 100644 --- a/src/ralph/networks/migrations/0008_auto_20160808_0719.py +++ b/src/ralph/networks/migrations/0008_auto_20160808_0719.py @@ -10,81 +10,87 @@ def _reserve_margin_addresses(network, bottom_count, top_count, IPAddress): - ips = [] - ips_query = IPAddress.objects.filter( - models.Q( - number__gte=network.min_ip + 1, - number__lte=network.min_ip + bottom_count + 1 - ) | - models.Q( - number__gte=network.max_ip - top_count, - number__lte=network.max_ip - ) + ips = [] + ips_query = IPAddress.objects.filter( + models.Q( + number__gte=network.min_ip + 1, + number__lte=network.min_ip + bottom_count + 1, + ) + | models.Q(number__gte=network.max_ip - top_count, number__lte=network.max_ip) + ) + existing_ips = set(ips_query.values_list("number", flat=True)) + to_create = set( + chain.from_iterable( + [ + range(int(network.min_ip + 1), int(network.min_ip + bottom_count + 1)), # noqa + range(int(network.max_ip - top_count), int(network.max_ip)), + ] ) - existing_ips = set(ips_query.values_list('number', flat=True)) - to_create = set(chain.from_iterable([ - range(int(network.min_ip + 1), int(network.min_ip + bottom_count + 1)), # noqa - range(int(network.max_ip - top_count), int(network.max_ip)) - ])) - to_create = to_create - existing_ips - for ip_as_int in to_create: - ips.append(IPAddress( + ) + to_create = to_create - existing_ips + for ip_as_int in to_create: + ips.append( + IPAddress( address=str(ipaddress.ip_address(ip_as_int)), number=ip_as_int, network=network, - status=IPADDRESS_STATUS_RESERVED - )) - print('Creating {} ips for {}'.format(len(ips), network)) - IPAddress.objects.bulk_create(ips) - ips_query.update(status=IPADDRESS_STATUS_RESERVED) + status=IPADDRESS_STATUS_RESERVED, + ) + ) + print("Creating {} ips for {}".format(len(ips), network)) + IPAddress.objects.bulk_create(ips) + ips_query.update(status=IPADDRESS_STATUS_RESERVED) def create_reserved_ips(apps, schema_editor): - IPAddress = apps.get_model('networks', 'IPAddress') - Network = apps.get_model('networks', 'Network') + IPAddress = apps.get_model("networks", "IPAddress") + Network = apps.get_model("networks", "Network") for network in Network.objects.all(): _reserve_margin_addresses( network, network.reserved_from_beginning, network.reserved_from_end, - IPAddress + IPAddress, ) def remove_reserved_ips(apps, schema_editor): - IPAddress = apps.get_model('networks', 'IPAddress') + IPAddress = apps.get_model("networks", "IPAddress") ips = IPAddress.objects.filter( - models.Q(ethernet__isnull=True) | ( - models.Q(ethernet__base_object__isnull=True) & - models.Q(ethernet__mac__isnull=False) + models.Q(ethernet__isnull=True) + | ( + models.Q(ethernet__base_object__isnull=True) + & models.Q(ethernet__mac__isnull=False) ), status=IPADDRESS_STATUS_RESERVED, gateway_network__isnull=True, ) - print('Removing {} reserved IPs'.format(ips.count())) + print("Removing {} reserved IPs".format(ips.count())) ips.delete() class Migration(migrations.Migration): - dependencies = [ - ('networks', '0007_auto_20160804_1409'), + ("networks", "0007_auto_20160804_1409"), ] operations = [ migrations.AddField( - model_name='network', - name='reserved_from_beginning', - field=models.PositiveIntegerField(help_text='Number of addresses to be omitted in DHCP automatic assignmentcounted from the first IP in range (excluding network address)', default=10), + model_name="network", + name="reserved_from_beginning", + field=models.PositiveIntegerField( + help_text="Number of addresses to be omitted in DHCP automatic assignmentcounted from the first IP in range (excluding network address)", + default=10, + ), ), migrations.AddField( - model_name='network', - name='reserved_from_end', - field=models.PositiveIntegerField(help_text='Number of addresses to be omitted in DHCP automatic assignmentcounted from the last IP in range (excluding broadcast address)', default=0), - ), - migrations.RunPython( - remove_reserved_ips, - reverse_code=create_reserved_ips + model_name="network", + name="reserved_from_end", + field=models.PositiveIntegerField( + help_text="Number of addresses to be omitted in DHCP automatic assignmentcounted from the last IP in range (excluding broadcast address)", + default=0, + ), ), + migrations.RunPython(remove_reserved_ips, reverse_code=create_reserved_ips), ] diff --git a/src/ralph/networks/migrations/0009_auto_20160823_0921.py b/src/ralph/networks/migrations/0009_auto_20160823_0921.py index cc32eff54e..1964d201d4 100644 --- a/src/ralph/networks/migrations/0009_auto_20160823_0921.py +++ b/src/ralph/networks/migrations/0009_auto_20160823_0921.py @@ -1,20 +1,25 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('networks', '0008_auto_20160808_0719'), + ("networks", "0008_auto_20160808_0719"), ] operations = [ migrations.AlterField( - model_name='ipaddress', - name='hostname', - field=ralph.lib.mixins.fields.NullableCharField(null=True, blank=True, verbose_name='hostname', default=None, max_length=255), + model_name="ipaddress", + name="hostname", + field=ralph.lib.mixins.fields.NullableCharField( + null=True, + blank=True, + verbose_name="hostname", + default=None, + max_length=255, + ), ), ] diff --git a/src/ralph/networks/migrations/0010_auto_20170216_1230.py b/src/ralph/networks/migrations/0010_auto_20170216_1230.py index 0fb114654c..c9c32a1f39 100644 --- a/src/ralph/networks/migrations/0010_auto_20170216_1230.py +++ b/src/ralph/networks/migrations/0010_auto_20170216_1230.py @@ -6,15 +6,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0009_auto_20160823_0921'), + ("networks", "0009_auto_20160823_0921"), ] operations = [ migrations.AlterField( - model_name='network', - name='gateway', - field=models.ForeignKey(to='networks.IPAddress', blank=True, on_delete=django.db.models.deletion.SET_NULL, verbose_name='Gateway address', null=True, related_name='gateway_network'), + model_name="network", + name="gateway", + field=models.ForeignKey( + to="networks.IPAddress", + blank=True, + on_delete=django.db.models.deletion.SET_NULL, + verbose_name="Gateway address", + null=True, + related_name="gateway_network", + ), ), ] diff --git a/src/ralph/networks/migrations/0011_add_dns_servers_group.py b/src/ralph/networks/migrations/0011_add_dns_servers_group.py index 4bdd99195c..e886d44525 100644 --- a/src/ralph/networks/migrations/0011_add_dns_servers_group.py +++ b/src/ralph/networks/migrations/0011_add_dns_servers_group.py @@ -6,68 +6,67 @@ def move_m2m_to_dns_server_group(apps, schema_editor): - Network = apps.get_model('networks', 'Network') - DNSServer = apps.get_model('dhcp', 'DNSServer') - DNSServerGroup = apps.get_model('dhcp', 'DNSServerGroup') - DNSServerGroupOrder = apps.get_model('dhcp', 'DNSServerGroupOrder') + Network = apps.get_model("networks", "Network") + DNSServer = apps.get_model("dhcp", "DNSServer") + DNSServerGroup = apps.get_model("dhcp", "DNSServerGroup") + DNSServerGroupOrder = apps.get_model("dhcp", "DNSServerGroupOrder") created_dns_servers_group_counter = 1 dns_group_list = [] for network in Network.objects.all(): if not network.dns_servers.count(): continue dns_group_list.append( - tuple(network.dns_servers.values_list( - 'id', flat=True - ).order_by('id')) + tuple(network.dns_servers.values_list("id", flat=True).order_by("id")) ) dns_servers_to_dns_group_mapper = {} for dns_servers in set(dns_group_list): dns_server_group = DNSServerGroup.objects.create( - name='DNS server group #{}'.format(created_dns_servers_group_counter) + name="DNS server group #{}".format(created_dns_servers_group_counter) ) created_dns_servers_group_counter += 1 for idx, server_id in enumerate(dns_servers): DNSServerGroupOrder.objects.create( dns_server_group=dns_server_group, dns_server=DNSServer.objects.get(id=server_id), - order=idx * 10 + order=idx * 10, ) dns_servers_to_dns_group_mapper[dns_servers] = dns_server_group for network in Network.objects.all(): - key = tuple(network.dns_servers.values_list( - 'id', flat=True - ).order_by('id')) + key = tuple(network.dns_servers.values_list("id", flat=True).order_by("id")) if not key: continue dns_server_group = dns_servers_to_dns_group_mapper[key] network.dns_servers_group = dns_server_group - network.save(update_fields=['dns_servers_group']) + network.save(update_fields=["dns_servers_group"]) def move_dns_server_group_to_m2m(apps, schema_editor): - Network = apps.get_model('networks', 'Network') + Network = apps.get_model("networks", "Network") for network in Network.objects.filter(dns_servers_group__isnull=False): dns_servers = network.dns_servers_group.servers.all() network.dns_servers.add(*dns_servers) class Migration(migrations.Migration): - dependencies = [ - ('dhcp', '0005_change_related_name'), - ('networks', '0010_auto_20170216_1230'), + ("dhcp", "0005_change_related_name"), + ("networks", "0010_auto_20170216_1230"), ] operations = [ migrations.AddField( - model_name='network', - name='dns_servers_group', - field=models.ForeignKey(to='dhcp.DNSServerGroup', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="network", + name="dns_servers_group", + field=models.ForeignKey( + to="dhcp.DNSServerGroup", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.RunPython( - move_m2m_to_dns_server_group, - reverse_code=move_dns_server_group_to_m2m - ) + move_m2m_to_dns_server_group, reverse_code=move_dns_server_group_to_m2m + ), ] diff --git a/src/ralph/networks/migrations/0012_remove_network_dns_servers.py b/src/ralph/networks/migrations/0012_remove_network_dns_servers.py index f7049e63a0..eacd86ff83 100644 --- a/src/ralph/networks/migrations/0012_remove_network_dns_servers.py +++ b/src/ralph/networks/migrations/0012_remove_network_dns_servers.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('networks', '0011_add_dns_servers_group'), + ("networks", "0011_add_dns_servers_group"), ] operations = [ migrations.RemoveField( - model_name='network', - name='dns_servers', + model_name="network", + name="dns_servers", ), ] diff --git a/src/ralph/networks/migrations/0013_auto_20171006_0947.py b/src/ralph/networks/migrations/0013_auto_20171006_0947.py index f89f7c5aab..97a12de9b8 100644 --- a/src/ralph/networks/migrations/0013_auto_20171006_0947.py +++ b/src/ralph/networks/migrations/0013_auto_20171006_0947.py @@ -6,15 +6,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0012_remove_network_dns_servers'), + ("networks", "0012_remove_network_dns_servers"), ] operations = [ migrations.AlterField( - model_name='network', - name='dns_servers_group', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='dhcp.DNSServerGroup', null=True, blank=True), + model_name="network", + name="dns_servers_group", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="dhcp.DNSServerGroup", + null=True, + blank=True, + ), ), ] diff --git a/src/ralph/networks/migrations/0014_auto_20171009_1030.py b/src/ralph/networks/migrations/0014_auto_20171009_1030.py index 0792a422a0..6852a55a70 100644 --- a/src/ralph/networks/migrations/0014_auto_20171009_1030.py +++ b/src/ralph/networks/migrations/0014_auto_20171009_1030.py @@ -6,15 +6,20 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0013_auto_20171006_0947'), + ("networks", "0013_auto_20171006_0947"), ] operations = [ migrations.AlterField( - model_name='network', - name='dns_servers_group', - field=models.ForeignKey(to='dhcp.DNSServerGroup', related_name='networks', null=True, blank=True, on_delete=django.db.models.deletion.PROTECT), + model_name="network", + name="dns_servers_group", + field=models.ForeignKey( + to="dhcp.DNSServerGroup", + related_name="networks", + null=True, + blank=True, + on_delete=django.db.models.deletion.PROTECT, + ), ), ] diff --git a/src/ralph/networks/migrations/0015_auto_20211115_1125.py b/src/ralph/networks/migrations/0015_auto_20211115_1125.py index d2dee365fd..bdc44b7929 100644 --- a/src/ralph/networks/migrations/0015_auto_20211115_1125.py +++ b/src/ralph/networks/migrations/0015_auto_20211115_1125.py @@ -1,20 +1,25 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('networks', '0014_auto_20171009_1030'), + ("networks", "0014_auto_20171009_1030"), ] operations = [ migrations.AlterField( - model_name='ipaddress', - name='hostname', - field=ralph.lib.mixins.fields.NullableCharFieldWithAutoStrip(verbose_name='hostname', max_length=255, blank=True, null=True, default=None), + model_name="ipaddress", + name="hostname", + field=ralph.lib.mixins.fields.NullableCharFieldWithAutoStrip( + verbose_name="hostname", + max_length=255, + blank=True, + null=True, + default=None, + ), ), ] diff --git a/src/ralph/networks/migrations/0016_auto_20240621_1200.py b/src/ralph/networks/migrations/0016_auto_20240621_1200.py index 67cabbc8a8..22fbd16186 100644 --- a/src/ralph/networks/migrations/0016_auto_20240621_1200.py +++ b/src/ralph/networks/migrations/0016_auto_20240621_1200.py @@ -6,25 +6,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0015_auto_20211115_1125'), + ("networks", "0015_auto_20211115_1125"), ] operations = [ migrations.AlterField( - model_name='network', - name='level', + model_name="network", + name="level", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='network', - name='lft', + model_name="network", + name="lft", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='network', - name='rght', + model_name="network", + name="rght", field=models.PositiveIntegerField(editable=False), ), ] diff --git a/src/ralph/networks/migrations/0016_auto_20240924_1155.py b/src/ralph/networks/migrations/0016_auto_20240924_1155.py index afbf0aa1f0..ef0bc00996 100644 --- a/src/ralph/networks/migrations/0016_auto_20240924_1155.py +++ b/src/ralph/networks/migrations/0016_auto_20240924_1155.py @@ -7,15 +7,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0015_auto_20211115_1125'), + ("networks", "0015_auto_20211115_1125"), ] operations = [ migrations.AlterField( - model_name='network', - name='terminators', - field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField(blank=True, to='assets.BaseObject', verbose_name='network terminators'), + model_name="network", + name="terminators", + field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField( + blank=True, to="assets.BaseObject", verbose_name="network terminators" + ), ), ] diff --git a/src/ralph/networks/migrations/0017_merge_20240925_1101.py b/src/ralph/networks/migrations/0017_merge_20240925_1101.py index a35ca916e8..9d46c65695 100644 --- a/src/ralph/networks/migrations/0017_merge_20240925_1101.py +++ b/src/ralph/networks/migrations/0017_merge_20240925_1101.py @@ -6,11 +6,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('networks', '0016_auto_20240621_1200'), - ('networks', '0016_auto_20240924_1155'), + ("networks", "0016_auto_20240621_1200"), + ("networks", "0016_auto_20240924_1155"), ] - operations = [ - ] + operations = [] diff --git a/src/ralph/networks/models/__init__.py b/src/ralph/networks/models/__init__.py index 6e7bb92e85..6c49e408a5 100644 --- a/src/ralph/networks/models/__init__.py +++ b/src/ralph/networks/models/__init__.py @@ -4,14 +4,14 @@ IPAddress, Network, NetworkEnvironment, - NetworkKind + NetworkKind, ) __all__ = [ - 'DiscoveryQueue', - 'IPAddress', - 'IPAddressStatus', - 'Network', - 'NetworkEnvironment', - 'NetworkKind', + "DiscoveryQueue", + "IPAddress", + "IPAddressStatus", + "Network", + "NetworkEnvironment", + "NetworkKind", ] diff --git a/src/ralph/networks/models/choices.py b/src/ralph/networks/models/choices.py index 67da17faf4..35a6b36b1c 100644 --- a/src/ralph/networks/models/choices.py +++ b/src/ralph/networks/models/choices.py @@ -4,5 +4,5 @@ class IPAddressStatus(Choices): _ = Choices.Choice - used = _('used (fixed address in DHCP)') - reserved = _('reserved').extra(help_text=_('Exclude from DHCP')) + used = _("used (fixed address in DHCP)") + reserved = _("reserved").extra(help_text=_("Exclude from DHCP")) diff --git a/src/ralph/networks/models/networks.py b/src/ralph/networks/models/networks.py index c888620bf4..979b57b4e5 100644 --- a/src/ralph/networks/models/networks.py +++ b/src/ralph/networks/models/networks.py @@ -16,16 +16,13 @@ from ralph.assets.models import AssetLastHostname, Ethernet from ralph.dns.dnsaas import DNSaaS from ralph.lib import network as network_tools -from ralph.lib.mixins.fields import ( - NullableCharField, - NullableCharFieldWithAutoStrip -) +from ralph.lib.mixins.fields import NullableCharField, NullableCharFieldWithAutoStrip from ralph.lib.mixins.models import ( AdminAbsoluteUrlMixin, LastSeenMixin, NamedMixin, PreviousStateMixin, - TimeStampMixin + TimeStampMixin, ) from ralph.lib.polymorphic.fields import PolymorphicManyToManyField from ralph.networks.fields import IPNetwork @@ -38,79 +35,74 @@ def is_in_dnsaas(ip): if not settings.ENABLE_DNSAAS_INTEGRATION: return False dnsaas_client = DNSaaS() - url = dnsaas_client.build_url( - 'records', get_params=[('ip', ip), ('type', 'A')] - ) + url = dnsaas_client.build_url("records", get_params=[("ip", ip), ("type", "A")]) return len(dnsaas_client.get_api_result(url)) > 0 class NetworkKind(AdminAbsoluteUrlMixin, NamedMixin, models.Model): class Meta: - verbose_name = _('network kind') - verbose_name_plural = _('network kinds') - ordering = ('name',) + verbose_name = _("network kind") + verbose_name_plural = _("network kinds") + ordering = ("name",) class NetworkEnvironment( - AdminAbsoluteUrlMixin, - TimeStampMixin, - NamedMixin, - models.Model + AdminAbsoluteUrlMixin, TimeStampMixin, NamedMixin, models.Model ): data_center = models.ForeignKey( - 'data_center.DataCenter', - verbose_name=_('data center'), - on_delete=models.CASCADE + "data_center.DataCenter", + verbose_name=_("data center"), + on_delete=models.CASCADE, ) queue = models.ForeignKey( - 'DiscoveryQueue', - verbose_name=_('discovery queue'), + "DiscoveryQueue", + verbose_name=_("discovery queue"), null=True, blank=True, on_delete=models.SET_NULL, ) hostname_template_counter_length = models.PositiveIntegerField( - verbose_name=_('hostname template counter length'), + verbose_name=_("hostname template counter length"), default=4, ) hostname_template_prefix = models.CharField( - verbose_name=_('hostname template prefix'), + verbose_name=_("hostname template prefix"), max_length=30, ) hostname_template_postfix = models.CharField( - verbose_name=_('hostname template postfix'), + verbose_name=_("hostname template postfix"), max_length=30, help_text=_( - 'This value will be used as a postfix when generating new hostname ' + "This value will be used as a postfix when generating new hostname " 'in this network environment. For example, when prefix is "s1", ' 'postfix is ".mydc.net" and counter length is 4, following ' - ' hostnames will be generated: s10000.mydc.net, s10001.mydc.net, ..' - ', s19999.mydc.net.' - ) + " hostnames will be generated: s10000.mydc.net, s10001.mydc.net, .." + ", s19999.mydc.net." + ), ) domain = NullableCharField( - verbose_name=_('domain'), + verbose_name=_("domain"), max_length=255, blank=True, null=True, - help_text=_('Used in DHCP configuration.'), + help_text=_("Used in DHCP configuration."), ) remarks = models.TextField( - verbose_name=_('remarks'), - help_text=_('Additional information.'), + verbose_name=_("remarks"), + help_text=_("Additional information."), blank=True, null=True, ) use_hostname_counter = models.BooleanField( default=True, - help_text='If set to false hostname based on already added hostnames.' + help_text="If set to false hostname based on already added hostnames.", ) def __str__(self): return self.name class Meta: - ordering = ('name',) + ordering = ("name",) @property def HOSTNAME_MODELS(self): @@ -127,17 +119,16 @@ def next_free_hostname(self): """ if self.use_hostname_counter: return AssetLastHostname.get_next_free_hostname( - self.hostname_template_prefix, - self.hostname_template_postfix, - self.hostname_template_counter_length, - self.check_hostname_is_available + self.hostname_template_prefix, + self.hostname_template_postfix, + self.hostname_template_counter_length, + self.check_hostname_is_available, ) else: result = self.next_hostname_without_model_counter() return result def check_hostname_is_available(self, hostname): - if not hostname: return False @@ -175,12 +166,15 @@ def current_counter_without_model(self): stop = -len(self.hostname_template_postfix) hostnames = [] for model_class in self.HOSTNAME_MODELS: - item = model_class.objects.filter( - hostname__iregex='{}[0-9]+{}'.format( - self.hostname_template_prefix, - self.hostname_template_postfix + item = ( + model_class.objects.filter( + hostname__iregex="{}[0-9]+{}".format( + self.hostname_template_prefix, self.hostname_template_postfix + ) ) - ).order_by('-hostname').first() + .order_by("-hostname") + .first() + ) if item and item.hostname: hostnames.append(item.hostname[start:stop]) counter = 0 @@ -209,11 +203,9 @@ def next_hostname_without_model_counter(self): hostname = AssetLastHostname( prefix=self.hostname_template_prefix, counter=self.next_counter_without_model(), - postfix=self.hostname_template_postfix - ) - return hostname.formatted_hostname( - self.hostname_template_counter_length + postfix=self.hostname_template_postfix, ) + return hostname.formatted_hostname(self.hostname_template_counter_length) class NetworkMixin(object): @@ -239,108 +231,115 @@ class Network( TimeStampMixin, NetworkMixin, MPTTModel, - models.Model + models.Model, ): """ Class for networks. """ - _parent_attr = 'parent' + + _parent_attr = "parent" parent = TreeForeignKey( - 'self', + "self", null=True, blank=True, - related_name='children', + related_name="children", db_index=True, editable=False, - on_delete=models.CASCADE + on_delete=models.CASCADE, ) address = IPNetwork( - verbose_name=_('network address'), - help_text=_('Presented as string (e.g. 192.168.0.0/24)'), - unique=True + verbose_name=_("network address"), + help_text=_("Presented as string (e.g. 192.168.0.0/24)"), + unique=True, ) - address._filter_title = _('Network Class') + address._filter_title = _("Network Class") gateway = models.ForeignKey( - 'IPAddress', verbose_name=_('Gateway address'), null=True, blank=True, - related_name='gateway_network', on_delete=models.SET_NULL, + "IPAddress", + verbose_name=_("Gateway address"), + null=True, + blank=True, + related_name="gateway_network", + on_delete=models.SET_NULL, ) remarks = models.TextField( - verbose_name=_('remarks'), - help_text=_('Additional information.'), + verbose_name=_("remarks"), + help_text=_("Additional information."), blank=True, - default='', + default="", ) # TODO: create ManyToManyBaseObjectField to avoid through table terminators = PolymorphicManyToManyField( - 'assets.BaseObject', - verbose_name=_('network terminators'), - blank=True + "assets.BaseObject", verbose_name=_("network terminators"), blank=True ) vlan = models.PositiveIntegerField( - verbose_name=_('VLAN number'), + verbose_name=_("VLAN number"), null=True, blank=True, default=None, ) racks = models.ManyToManyField( - 'data_center.Rack', - verbose_name=_('racks'), + "data_center.Rack", + verbose_name=_("racks"), blank=True, ) network_environment = models.ForeignKey( NetworkEnvironment, - verbose_name=_('environment'), + verbose_name=_("environment"), null=True, blank=True, on_delete=models.SET_NULL, ) network_environment._autocomplete = False min_ip = models.DecimalField( - verbose_name=_('smallest IP number'), + verbose_name=_("smallest IP number"), editable=False, max_digits=39, decimal_places=0, ) max_ip = models.DecimalField( - verbose_name=_('largest IP number'), + verbose_name=_("largest IP number"), editable=False, max_digits=39, decimal_places=0, ) kind = models.ForeignKey( NetworkKind, - verbose_name=_('network kind'), + verbose_name=_("network kind"), on_delete=models.SET_NULL, blank=True, null=True, ) dhcp_broadcast = models.BooleanField( - verbose_name=_('Broadcast in DHCP configuration'), + verbose_name=_("Broadcast in DHCP configuration"), default=True, db_index=True, ) service_env = models.ForeignKey( - 'assets.ServiceEnvironment', related_name='networks', null=True, - default=None, blank=True, on_delete=models.CASCADE + "assets.ServiceEnvironment", + related_name="networks", + null=True, + default=None, + blank=True, + on_delete=models.CASCADE, ) dns_servers_group = models.ForeignKey( - 'dhcp.DNSServerGroup', + "dhcp.DNSServerGroup", null=True, blank=True, - related_name='networks', + related_name="networks", on_delete=models.PROTECT, ) reserved_from_beginning = models.PositiveIntegerField( help_text=_( - 'Number of addresses to be omitted in DHCP automatic assignment' - 'counted from the first IP in range (excluding network address)' + "Number of addresses to be omitted in DHCP automatic assignment" + "counted from the first IP in range (excluding network address)" ), default=settings.DEFAULT_NETWORK_BOTTOM_MARGIN, ) reserved_from_end = models.PositiveIntegerField( help_text=_( - 'Number of addresses to be omitted in DHCP automatic assignment' - 'counted from the last IP in range (excluding broadcast address)' + "Number of addresses to be omitted in DHCP automatic assignment" + "counted from the last IP in range (excluding broadcast address)" ), default=settings.DEFAULT_NETWORK_TOP_MARGIN, ) @@ -365,7 +364,7 @@ def netmask(self): def netmask_dot_decimal(self): """Returns netmask in dot-decimal notaion (e.g. 255.255.255.0).""" return socket.inet_ntoa( - struct.pack('>I', (0xffffffff << (32 - self.netmask)) & 0xffffffff) + struct.pack(">I", (0xFFFFFFFF << (32 - self.netmask)) & 0xFFFFFFFF) ) @property @@ -403,16 +402,16 @@ def reserved_top(self): return self.reserved_from_end class Meta: - verbose_name = _('network') - verbose_name_plural = _('networks') - unique_together = ('min_ip', 'max_ip') + verbose_name = _("network") + verbose_name_plural = _("networks") + unique_together = ("min_ip", "max_ip") def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._old_address = self.address def __str__(self): - return '{} ({} | VLAN: {})'.format(self.name, self.address, self.vlan) + return "{} ({} | VLAN: {})".format(self.name, self.address, self.vlan) def save(self, *args, **kwargs): """ @@ -433,16 +432,10 @@ def save(self, *args, **kwargs): self.gateway.status = IPAddressStatus.reserved self.gateway.save() - update_subnetworks_parent = kwargs.pop( - 'update_subnetworks_parent', True - ) + update_subnetworks_parent = kwargs.pop("update_subnetworks_parent", True) creating = not self.pk # store previous subnetworks to update them when address has changed - if ( - self._has_address_changed and - update_subnetworks_parent and - not creating - ): + if self._has_address_changed and update_subnetworks_parent and not creating: prev_subnetworks = self.get_immediate_subnetworks() else: prev_subnetworks = [] @@ -466,7 +459,7 @@ def delete(self): # Save fake address so that all children of network changed its # parent, only then network is removed. with transaction.atomic(): - self.address = '0.0.0.0/32' + self.address = "0.0.0.0/32" self.save() super().delete() @@ -500,13 +493,12 @@ def _assign_new_ips_to_network(self): (possibly) assign them to current network (according to rules in IPAddress.save) """ - for ip in IPAddress.objects.exclude( - network=self, - ).exclude( - network__in=self.get_subnetworks() - ).filter( - number__gte=self.min_ip, - number__lte=self.max_ip + for ip in ( + IPAddress.objects.exclude( + network=self, + ) + .exclude(network__in=self.get_subnetworks()) + .filter(number__gte=self.min_ip, number__lte=self.max_ip) ): # call save instead of update - ip might be assigned to another # (smaller) network, which became subnetwork of current network @@ -530,11 +522,11 @@ def get_immediate_subnetworks(self): return self.get_children() def get_first_free_ip(self): - used_ips = set(IPAddress.objects.filter( - number__range=(self.min_ip, self.max_ip) - ).values_list( - 'number', flat=True - )) + used_ips = set( + IPAddress.objects.filter( + number__range=(self.min_ip, self.max_ip) + ).values_list("number", flat=True) + ) # add one to omit network address min_ip = int(self.min_ip + 1 + self.reserved_from_beginning) # subtract 1 to omit broadcast address @@ -544,9 +536,7 @@ def get_first_free_ip(self): if free_ip_as_int not in used_ips: next_free_ip = ipaddress.ip_address(free_ip_as_int) if is_in_dnsaas(next_free_ip): - logger.warning( - 'IP %s is already in DNS', next_free_ip - ) + logger.warning("IP %s is already in DNS", next_free_ip) else: return next_free_ip @@ -561,26 +551,26 @@ def search_networks(self): then by max_ip ascending, to get smallest ancestor network containing current network. """ - nets = Network.objects.filter( - min_ip__lte=self.min_ip, - max_ip__gte=self.max_ip - ).exclude(pk=self.id).order_by('-min_ip', 'max_ip') + nets = ( + Network.objects.filter(min_ip__lte=self.min_ip, max_ip__gte=self.max_ip) + .exclude(pk=self.id) + .order_by("-min_ip", "max_ip") + ) return nets # TODO: remove class DiscoveryQueue(AdminAbsoluteUrlMixin, NamedMixin, models.Model): - class Meta: - verbose_name = _('discovery queue') - verbose_name_plural = _('discovery queues') - ordering = ('name',) + verbose_name = _("discovery queue") + verbose_name_plural = _("discovery queues") + ordering = ("name",) class IPAddressQuerySet(models.QuerySet): def create(self, base_object=None, mac=None, label=None, **kwargs): with transaction.atomic(): - eth = kwargs.pop('ethernet', None) + eth = kwargs.pop("ethernet", None) if base_object and not eth: eth = Ethernet.objects.create( base_object=base_object, mac=mac, label=label @@ -596,9 +586,9 @@ class IPAddress( TimeStampMixin, PreviousStateMixin, NetworkMixin, - models.Model + models.Model, ): - _parent_attr = 'network' + _parent_attr = "network" ethernet = models.OneToOneField( Ethernet, @@ -612,18 +602,18 @@ class IPAddress( null=True, default=None, editable=False, - related_name='ips', + related_name="ips", on_delete=models.SET_NULL, ) address = models.GenericIPAddressField( - verbose_name=_('IP address'), - help_text=_('Presented as string.'), + verbose_name=_("IP address"), + help_text=_("Presented as string."), unique=True, blank=False, null=False, ) hostname = NullableCharFieldWithAutoStrip( - verbose_name=_('hostname'), + verbose_name=_("hostname"), max_length=255, null=True, blank=True, @@ -631,8 +621,8 @@ class IPAddress( # TODO: unique ) number = models.DecimalField( - verbose_name=_('IP address'), - help_text=_('Presented as int.'), + verbose_name=_("IP address"), + help_text=_("Presented as int."), editable=False, unique=True, max_digits=39, @@ -640,16 +630,16 @@ class IPAddress( default=None, ) is_management = models.BooleanField( - verbose_name=_('Is management address'), + verbose_name=_("Is management address"), default=False, ) is_public = models.BooleanField( - verbose_name=_('Is public'), + verbose_name=_("Is public"), default=False, editable=False, ) is_gateway = models.BooleanField( - verbose_name=_('Is gateway'), + verbose_name=_("Is gateway"), default=False, ) status = models.PositiveSmallIntegerField( @@ -658,12 +648,12 @@ class IPAddress( ) dhcp_expose = models.BooleanField( default=False, - verbose_name=_('Expose in DHCP'), + verbose_name=_("Expose in DHCP"), ) class Meta: - verbose_name = _('IP address') - verbose_name_plural = _('IP addresses') + verbose_name = _("IP address") + verbose_name_plural = _("IP addresses") objects = IPAddressQuerySet.as_manager() @@ -672,9 +662,9 @@ def __str__(self): def _hostname_is_unique_in_dc(self, hostname, dc): from ralph.dhcp.models import DHCPEntry + entries_with_hostname = DHCPEntry.objects.filter( - hostname=hostname, - network__network_environment__data_center=dc + hostname=hostname, network__network_environment__data_center=dc ) if self.pk: entries_with_hostname = entries_with_hostname.exclude(pk=self.pk) @@ -686,8 +676,7 @@ def validate_hostname_uniqueness_in_dc(self, hostname): dc = network.network_environment.data_center if not self._hostname_is_unique_in_dc(hostname, dc): raise ValidationError( - 'Hostname "{hostname}" is already exposed in DHCP in {dc}.' - .format( + 'Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( hostname=self.hostname, dc=dc ) ) @@ -699,22 +688,18 @@ def _validate_hostname_uniqueness_in_dc(self): def _validate_expose_in_dhcp_and_mac(self): if ( - (not self.ethernet_id or (self.ethernet and not self.ethernet.mac)) and # noqa - self.dhcp_expose + (not self.ethernet_id or (self.ethernet and not self.ethernet.mac)) # noqa + and self.dhcp_expose ): - raise ValidationError({ - 'dhcp_expose': ( - 'Cannot expose in DHCP without MAC address' - ) - }) + raise ValidationError( + {"dhcp_expose": ("Cannot expose in DHCP without MAC address")} + ) def _validate_expose_in_dhcp_and_hostname(self): if not self.hostname and self.dhcp_expose: - raise ValidationError({ - 'hostname': ( - 'Cannot expose in DHCP without hostname' - ) - }) + raise ValidationError( + {"hostname": ("Cannot expose in DHCP without hostname")} + ) def _validate_change_when_exposing_in_dhcp(self): """ @@ -725,15 +710,13 @@ def _validate_change_when_exposing_in_dhcp(self): old_obj = self.__class__._default_manager.get(pk=self.pk) if old_obj.dhcp_expose: for attr_name, field_name in [ - ('hostname', 'hostname'), - ('address', 'address'), - ('ethernet_id', 'ethernet'), + ("hostname", "hostname"), + ("address", "address"), + ("ethernet_id", "ethernet"), ]: if getattr(old_obj, attr_name) != getattr(self, attr_name): raise ValidationError( - 'Cannot change {} when exposing in DHCP'.format( - field_name - ) + "Cannot change {} when exposing in DHCP".format(field_name) ) def clean(self): @@ -755,9 +738,7 @@ def clean(self): def save(self, *args, **kwargs): if settings.CHECK_IP_HOSTNAME_ON_SAVE: if not self.address and self.hostname: - self.address = network_tools.hostname( - self.hostname, reverse=True - ) + self.address = network_tools.hostname(self.hostname, reverse=True) if not self.hostname and self.address: self.hostname = network_tools.hostname(self.address) if self.number and not self.address: @@ -797,9 +778,8 @@ def search_networks(self): """ int_value = int(self.ip) nets = Network.objects.filter( - min_ip__lte=int_value, - max_ip__gte=int_value - ).order_by('-min_ip', 'max_ip') + min_ip__lte=int_value, max_ip__gte=int_value + ).order_by("-min_ip", "max_ip") return nets @@ -809,13 +789,13 @@ def rebuild_handler(sender, **kwargs): Rebuild Network tree after migration of operations app. """ # post_migrate is called after each app's migrations - if sender.name == 'ralph.' + Network._meta.app_label: + if sender.name == "ralph." + Network._meta.app_label: try: Network.objects.rebuild() except ProgrammingError: # this may happen during unapplying initial migration for networks # app - logger.warning('ProgrammingError during Network rebuilding') + logger.warning("ProgrammingError during Network rebuilding") @receiver(pre_save, sender=NetworkEnvironment) @@ -824,13 +804,11 @@ def update_counter(sender, instance, **kwargs): return orig = NetworkEnvironment.objects.get(id=instance.id) - if ( - instance.use_hostname_counter and not orig.use_hostname_counter - ): + if instance.use_hostname_counter and not orig.use_hostname_counter: obj, created = AssetLastHostname.objects.update_or_create( prefix=instance.hostname_template_prefix, postfix=instance.hostname_template_postfix, defaults={ - 'counter': instance.current_counter_without_model(), - } + "counter": instance.current_counter_without_model(), + }, ) diff --git a/src/ralph/networks/receivers.py b/src/ralph/networks/receivers.py index 1f84d76674..3debb58bfe 100644 --- a/src/ralph/networks/receivers.py +++ b/src/ralph/networks/receivers.py @@ -14,12 +14,8 @@ def _should_send_dnsaas_request(ip_instance): Ethernet) and it's not CloudHost. """ eth = ip_instance.ethernet - invalid_content_types = ContentType.objects.get_for_models( - *INVALID_MODELS - ).values() - return ( - eth and eth.base_object.content_type not in invalid_content_types - ) + invalid_content_types = ContentType.objects.get_for_models(*INVALID_MODELS).values() + return eth and eth.base_object.content_type not in invalid_content_types def _get_connected_service_uid(ip_instance): @@ -38,15 +34,15 @@ def _get_connected_service_uid(ip_instance): def update_dns_record(instance, created, *args, **kwargs): if not _should_send_dnsaas_request(instance): return - keys = ['address', 'hostname'] + keys = ["address", "hostname"] old = {key: instance._previous_state[key] for key in keys} new = {key: instance.__dict__[key] for key in keys} - if old != new and old['hostname'] is not None: + if old != new and old["hostname"] is not None: data_to_send = { - 'old': old, - 'new': new, - 'service_uid': _get_connected_service_uid(instance), - 'action': 'add' if created else 'update' + "old": old, + "new": new, + "service_uid": _get_connected_service_uid(instance), + "action": "add" if created else "update", } DNSaaS().send_ipaddress_data(data_to_send) @@ -54,8 +50,6 @@ def update_dns_record(instance, created, *args, **kwargs): def delete_dns_record(instance, *args, **kwargs): if not _should_send_dnsaas_request(instance): return - DNSaaS().send_ipaddress_data({ - 'address': instance.address, - 'hostname': instance.hostname, - 'action': 'delete' - }) + DNSaaS().send_ipaddress_data( + {"address": instance.address, "hostname": instance.hostname, "action": "delete"} + ) diff --git a/src/ralph/networks/tests/factories.py b/src/ralph/networks/tests/factories.py index 14198e99fb..46e619c20f 100644 --- a/src/ralph/networks/tests/factories.py +++ b/src/ralph/networks/tests/factories.py @@ -10,32 +10,34 @@ IPAddress, Network, NetworkEnvironment, - NetworkKind + NetworkKind, ) class NetworkKindFactory(DjangoModelFactory): - name = factory.Iterator(['office', 'DC', 'HA', 'L3']) + name = factory.Iterator(["office", "DC", "HA", "L3"]) class Meta: model = NetworkKind - django_get_or_create = ['name'] + django_get_or_create = ["name"] class NetworkEnvironmentFactory(DjangoModelFactory): - name = factory.Iterator(['prod1', 'test1', 'preprod1', 'dev1']) + name = factory.Iterator(["prod1", "test1", "preprod1", "dev1"]) data_center = factory.SubFactory(DataCenterFactory) - hostname_template_prefix = 's1' - hostname_template_postfix = '.mydc.net' + hostname_template_prefix = "s1" + hostname_template_postfix = ".mydc.net" class Meta: model = NetworkEnvironment - django_get_or_create = ['name'] + django_get_or_create = ["name"] class NetworkFactory(DjangoModelFactory): - address = factory.Sequence(lambda n: '{}.{}.{}.0/24'.format(n // 256**2 + 1, n // 256, n % 256)) - name = factory.Sequence(lambda n: 'Net ' + str(n)) + address = factory.Sequence( + lambda n: "{}.{}.{}.0/24".format(n // 256**2 + 1, n // 256, n % 256) + ) + name = factory.Sequence(lambda n: "Net " + str(n)) network_environment = factory.SubFactory(NetworkEnvironmentFactory) @factory.post_generation @@ -53,10 +55,8 @@ class Meta: class IPAddressFactory(DjangoModelFactory): - address = factory.Faker('ipv4') - hostname = FuzzyText( - prefix='ralph.', suffix='.allegro.pl', length=40 - ) + address = factory.Faker("ipv4") + hostname = FuzzyText(prefix="ralph.", suffix=".allegro.pl", length=40) ethernet = factory.SubFactory(EthernetFactory) class Meta: @@ -69,10 +69,7 @@ def _get_network_address(ip, mask=24): """ ip = ipaddress.ip_address(ip) return ipaddress.ip_network( - '{}/{}'.format( - ipaddress.ip_address(int(ip) & (2**32 - 1) << (32 - mask)), - mask - ) + "{}/{}".format(ipaddress.ip_address(int(ip) & (2**32 - 1) << (32 - mask)), mask) ) @@ -80,10 +77,8 @@ class IPAddressWithNetworkFactory(IPAddressFactory): network = factory.SubFactory( NetworkFactory, address=factory.LazyAttribute( - lambda ipaddress: _get_network_address( - ipaddress.factory_parent.address - ) - ) + lambda ipaddress: _get_network_address(ipaddress.factory_parent.address) + ), ) diff --git a/src/ralph/networks/tests/test_admin.py b/src/ralph/networks/tests/test_admin.py index cdec4e9554..28e7da70d1 100644 --- a/src/ralph/networks/tests/test_admin.py +++ b/src/ralph/networks/tests/test_admin.py @@ -6,22 +6,20 @@ class NetworkAdminTestCase(TestCase): def setUp(self): - self.network = NetworkFactory(address='10.20.30.0/24') - self.ip1 = IPAddressFactory(address='10.20.30.40') - self.ip2 = IPAddressFactory(address='10.20.30.41') - self.ip_other = IPAddressFactory(address='10.30.30.40') + self.network = NetworkFactory(address="10.20.30.0/24") + self.ip1 = IPAddressFactory(address="10.20.30.40") + self.ip2 = IPAddressFactory(address="10.20.30.41") + self.ip_other = IPAddressFactory(address="10.30.30.40") self.user = get_user_model().objects.create_superuser( - username='root', - password='password', - email='email@email.pl' + username="root", password="password", email="email@email.pl" ) - result = self.client.login(username='root', password='password') + result = self.client.login(username="root", password="password") self.assertEqual(result, True) self.factory = RequestFactory() def test_admin_view_should_show_addresses_in_network(self): response = self.client.get(self.network.get_absolute_url()) - self.assertContains(response, '10.20.30.40') - self.assertContains(response, '10.20.30.41') - self.assertNotContains(response, '10.30.30.40') + self.assertContains(response, "10.20.30.40") + self.assertContains(response, "10.20.30.41") + self.assertNotContains(response, "10.30.30.40") diff --git a/src/ralph/networks/tests/test_api.py b/src/ralph/networks/tests/test_api.py index 28f4c03ab5..3d08e49bed 100644 --- a/src/ralph/networks/tests/test_api.py +++ b/src/ralph/networks/tests/test_api.py @@ -12,139 +12,131 @@ class IPAddressAPITests(RalphAPITestCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.net = NetworkFactory(address='127.0.0.0/24') + cls.net = NetworkFactory(address="127.0.0.0/24") cls.eth = EthernetFactory() def setUp(self): super().setUp() - self.ip1 = IPAddressFactory(address='127.0.0.1') + self.ip1 = IPAddressFactory(address="127.0.0.1") self.ip1.ethernet.refresh_from_db() # to update mac - self.ip_with_dhcp = IPAddressFactory( - address='127.0.0.2', dhcp_expose=True - ) + self.ip_with_dhcp = IPAddressFactory(address="127.0.0.2", dhcp_expose=True) def test_get_ip_list_filter_by_dhcp_expose(self): - url = '{}?{}'.format(reverse('ipaddress-list'), 'dhcp_expose=True') + url = "{}?{}".format(reverse("ipaddress-list"), "dhcp_expose=True") # TODO: 1 and true should also work # see https://github.com/tomchristie/django-rest-framework/issues/2122 # for details - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_get_ip_list_filter_by_mac(self): - url = '{}?ethernet__mac={}'.format( - reverse('ipaddress-list'), self.ip1.ethernet.mac + url = "{}?ethernet__mac={}".format( + reverse("ipaddress-list"), self.ip1.ethernet.mac ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) def test_get_ip_list_filter_by_invalid_mac_400(self): - url = '{}?ethernet__mac={}'.format( - reverse('ipaddress-list'), '(none)' - ) - response = self.client.get(url, format='json') + url = "{}?ethernet__mac={}".format(reverse("ipaddress-list"), "(none)") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_get_ip_details(self): - url = reverse('ipaddress-detail', args=(self.ip1.id,)) - response = self.client.get(url, format='json') + url = reverse("ipaddress-detail", args=(self.ip1.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["ethernet"]["mac"], self.ip1.ethernet.mac) self.assertEqual( - response.data['ethernet']['mac'], self.ip1.ethernet.mac - ) - self.assertEqual( - response.data['ethernet']['ipaddress']['address'], self.ip1.address + response.data["ethernet"]["ipaddress"]["address"], self.ip1.address ) self.assertEqual( - response.data['ethernet']['base_object']['id'], - self.ip1.ethernet.base_object.id + response.data["ethernet"]["base_object"]["id"], + self.ip1.ethernet.base_object.id, ) def test_change_network_should_not_pass(self): - net = NetworkFactory(address='192.168.1.0/24') - data = {'network': net.id} - url = reverse('ipaddress-detail', args=(self.ip1.id,)) - response = self.client.patch(url, format='json', data=data) + net = NetworkFactory(address="192.168.1.0/24") + data = {"network": net.id} + url = reverse("ipaddress-detail", args=(self.ip1.id,)) + response = self.client.patch(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.ip1.refresh_from_db() self.assertEqual(self.ip1.network, self.net) def test_put_ip(self): data = { - 'address': '127.1.0.1', - 'hostname': 'another-hostname', - 'is_management': True, - 'is_gateway': True, - 'ethernet': self.eth.id, - 'dhcp_expose': True, + "address": "127.1.0.1", + "hostname": "another-hostname", + "is_management": True, + "is_gateway": True, + "ethernet": self.eth.id, + "dhcp_expose": True, } - url = reverse('ipaddress-detail', args=(self.ip1.id,)) - response = self.client.put(url, format='json', data=data) + url = reverse("ipaddress-detail", args=(self.ip1.id,)) + response = self.client.put(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.ip1.refresh_from_db() - self.assertEqual(self.ip1.address, '127.1.0.1') - self.assertEqual(self.ip1.hostname, 'another-hostname') + self.assertEqual(self.ip1.address, "127.1.0.1") + self.assertEqual(self.ip1.hostname, "another-hostname") self.assertTrue(self.ip1.is_management) self.assertTrue(self.ip1.dhcp_expose) self.assertTrue(self.ip1.is_gateway) self.assertEqual(self.ip1.ethernet, self.eth) def test_change_ip_address_already_occupied_should_not_pass(self): - data = {'address': '127.0.0.2'} - url = reverse('ipaddress-detail', args=(self.ip1.id,)) - response = self.client.patch(url, format='json', data=data) + data = {"address": "127.0.0.2"} + url = reverse("ipaddress-detail", args=(self.ip1.id,)) + response = self.client.patch(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('IP address with this IP address already exists.', response.data['address']) + self.assertIn( + "IP address with this IP address already exists.", response.data["address"] + ) def test_change_ip_address_with_dhcp_exposition_should_not_pass(self): - data = {'address': '127.0.0.3'} - url = reverse('ipaddress-detail', args=(self.ip_with_dhcp.id,)) - response = self.client.patch(url, format='json', data=data) + data = {"address": "127.0.0.3"} + url = reverse("ipaddress-detail", args=(self.ip_with_dhcp.id,)) + response = self.client.patch(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( - 'Cannot change address when exposing in DHCP', - response.data['__all__'] + "Cannot change address when exposing in DHCP", response.data["__all__"] ) def test_change_ip_hostname_with_dhcp_exposition_should_not_pass(self): - data = {'hostname': 'some-hostname'} - url = reverse('ipaddress-detail', args=(self.ip_with_dhcp.id,)) - response = self.client.patch(url, format='json', data=data) + data = {"hostname": "some-hostname"} + url = reverse("ipaddress-detail", args=(self.ip_with_dhcp.id,)) + response = self.client.patch(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( - 'Cannot change hostname when exposing in DHCP', - response.data['__all__'] + "Cannot change hostname when exposing in DHCP", response.data["__all__"] ) def test_change_ip_ethernet_with_dhcp_exposition_should_not_pass(self): - data = {'ethernet': self.eth.id} - url = reverse('ipaddress-detail', args=(self.ip_with_dhcp.id,)) - response = self.client.patch(url, format='json', data=data) + data = {"ethernet": self.eth.id} + url = reverse("ipaddress-detail", args=(self.ip_with_dhcp.id,)) + response = self.client.patch(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( - 'Cannot change ethernet when exposing in DHCP', - response.data['__all__'] + "Cannot change ethernet when exposing in DHCP", response.data["__all__"] ) def test_change_ip_dhcp_expose_with_dhcp_exposition_should_not_pass(self): - data = {'dhcp_expose': False} - url = reverse('ipaddress-detail', args=(self.ip_with_dhcp.id,)) - response = self.client.patch(url, format='json', data=data) + data = {"dhcp_expose": False} + url = reverse("ipaddress-detail", args=(self.ip_with_dhcp.id,)) + response = self.client.patch(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( - 'Cannot remove entry from DHCP. Use transition to do this.', - response.data['dhcp_expose'] + "Cannot remove entry from DHCP. Use transition to do this.", + response.data["dhcp_expose"], ) def test_delete_when_exposing_in_dhcp_should_not_pass(self): - url = reverse('ipaddress-detail', args=(self.ip_with_dhcp.id,)) - response = self.client.delete(url, format='json') + url = reverse("ipaddress-detail", args=(self.ip_with_dhcp.id,)) + response = self.client.delete(url, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( - 'Could not delete IPAddress when it is exposed in DHCP', - response.data + "Could not delete IPAddress when it is exposed in DHCP", response.data ) @@ -152,20 +144,18 @@ class NetworkAPITests(RalphAPITestCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.net1 = NetworkFactory(address='127.0.0.0/24') - cls.net2 = NetworkFactory(address='128.0.0.0/24') + cls.net1 = NetworkFactory(address="127.0.0.0/24") + cls.net2 = NetworkFactory(address="128.0.0.0/24") def test_get_ip_list_filter_by_mac(self): - url = '{}?address={}'.format( - reverse('network-list'), self.net1.address - ) - response = self.client.get(url, format='json') + url = "{}?address={}".format(reverse("network-list"), self.net1.address) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) - network = response.data['results'][0] - self.assertIsNotNone(network['min_ip']) - self.assertIsNotNone(network['max_ip']) + network = response.data["results"][0] + self.assertIsNotNone(network["min_ip"]) + self.assertIsNotNone(network["max_ip"]) def test_create_network_sets_min_and_max_ip_and_ignores_passed_value(self): data = { @@ -175,12 +165,11 @@ def test_create_network_sets_min_and_max_ip_and_ignores_passed_value(self): "max_ip": 111, } - url = reverse('network-list') - response = self.client.post(url, format='json', data=data) + url = reverse("network-list") + response = self.client.post(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) - network = Network.objects.get(pk=response.data['id']) + network = Network.objects.get(pk=response.data["id"]) # min and max ip are automatically assigned self.assertEqual(network.min_ip, 16777216) # 1.0.0.0 self.assertEqual(network.max_ip, 16842751) # 1.0.255.255 - diff --git a/src/ralph/networks/tests/test_filters.py b/src/ralph/networks/tests/test_filters.py index 2b8e78d69e..bac2709978 100644 --- a/src/ralph/networks/tests/test_filters.py +++ b/src/ralph/networks/tests/test_filters.py @@ -1,41 +1,40 @@ -from unittest import mock +from unittest import mock from django.contrib.admin.options import IncorrectLookupParameters -from django.test import override_settings, RequestFactory, TestCase +from django.test import RequestFactory, TestCase from django.test.client import RequestFactory from ralph.networks.admin import NetworkAdmin from ralph.networks.filters import ContainsIPAddressFilter from ralph.networks.models import Network -from ralph.networks.tests.factories import IPAddressFactory, NetworkFactory +from ralph.networks.tests.factories import NetworkFactory class NetworkFiltersTestCase(TestCase): - def setUp(self): super(NetworkFiltersTestCase, self).setUp() self.networks = ( - NetworkFactory(address='10.42.42.0/24'), - NetworkFactory(address='10.42.0.0/16'), - NetworkFactory(address='10.42.42.42/32'), - NetworkFactory(address='10.43.42.0/24'), - NetworkFactory(address='2001:db8:1234::/48') + NetworkFactory(address="10.42.42.0/24"), + NetworkFactory(address="10.42.0.0/16"), + NetworkFactory(address="10.42.42.42/32"), + NetworkFactory(address="10.43.42.0/24"), + NetworkFactory(address="2001:db8:1234::/48"), ) def get_member_ip_filter(self, member_ip): return ContainsIPAddressFilter( - field=Network._meta.get_field('max_ip'), + field=Network._meta.get_field("max_ip"), request=None, - params={'max_ip': member_ip}, + params={"max_ip": member_ip}, model=Network, model_admin=NetworkAdmin, - field_path='max_ip' + field_path="max_ip", ) def test_filter_member_ip_single_result(self): - member_ip = '10.43.42.10' - expected_network = '10.43.42.0/24' + member_ip = "10.43.42.10" + expected_network = "10.43.42.0/24" member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -46,8 +45,8 @@ def test_filter_member_ip_single_result(self): self.assertEqual(expected_network, results.pop()) def test_filter_member_ipv6_single_result(self): - member_ip = '2001:db8:1234:0000:0000:0000:0000:0042' - expected_network = '2001:db8:1234::/48' + member_ip = "2001:db8:1234:0000:0000:0000:0000:0042" + expected_network = "2001:db8:1234::/48" member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -58,8 +57,8 @@ def test_filter_member_ipv6_single_result(self): self.assertEqual(expected_network, results.pop()) def test_filter_member_ip_single_address_range_overlap(self): - member_ip = '10.42.42.10' - expected_networks = ['10.42.0.0/16', '10.42.42.0/24'] + member_ip = "10.42.42.10" + expected_networks = ["10.42.0.0/16", "10.42.42.0/24"] member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -69,10 +68,10 @@ def test_filter_member_ip_single_address_range_overlap(self): self.assertEqual(2, len(results)) self.assertEqual(expected_networks, results) - + def test_filter_member_ip_multiple_address_semicolon_range_overlap(self): - member_ip = '10.42.42.10;10.43.42.10' - expected_networks = ['10.42.0.0/16', '10.42.42.0/24', '10.43.42.0/24'] + member_ip = "10.42.42.10;10.43.42.10" + expected_networks = ["10.42.0.0/16", "10.42.42.0/24", "10.43.42.0/24"] member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -84,12 +83,8 @@ def test_filter_member_ip_multiple_address_semicolon_range_overlap(self): self.assertEqual(expected_networks, results) def test_filter_member_ip_multiple_address_ipv4_ipv6_range_overlap(self): - member_ip = '10.42.42.10;2001:db8:1234:0000:0000:0000:0000:0042' - expected_networks = [ - '10.42.0.0/16', - '10.42.42.0/24', - '2001:db8:1234::/48' - ] + member_ip = "10.42.42.10;2001:db8:1234:0000:0000:0000:0000:0042" + expected_networks = ["10.42.0.0/16", "10.42.42.0/24", "2001:db8:1234::/48"] member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -101,8 +96,8 @@ def test_filter_member_ip_multiple_address_ipv4_ipv6_range_overlap(self): self.assertEqual(expected_networks, results) def test_filter_member_ip_multiple_address_pipe_range_overlap(self): - member_ip = '10.42.42.10|10.43.42.10' - expected_networks = ['10.42.0.0/16', '10.42.42.0/24', '10.43.42.0/24'] + member_ip = "10.42.42.10|10.43.42.10" + expected_networks = ["10.42.0.0/16", "10.42.42.0/24", "10.43.42.0/24"] member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -114,7 +109,7 @@ def test_filter_member_ip_multiple_address_pipe_range_overlap(self): self.assertEqual(expected_networks, results) def test_filter_member_ip_no_results(self): - member_ip = '10.10.10.10' + member_ip = "10.10.10.10" member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -124,7 +119,7 @@ def test_filter_member_ip_no_results(self): self.assertEqual([], results) def test_filter_member_ip_empty_value(self): - member_ip = '' + member_ip = "" member_ip_filter = self.get_member_ip_filter(member_ip) queryset = member_ip_filter.queryset(None, Network.objects.all()) @@ -134,20 +129,16 @@ def test_filter_member_ip_empty_value(self): self.assertEqual(5, len(results)) def test_filter_member_invalid_input_raises_correct_valudation_error(self): - member_ip = 'DEADBEEF' + member_ip = "DEADBEEF" rf = RequestFactory() - fake_request = rf.get('/') + fake_request = rf.get("/") # NOTE(romcheg): Need to attach _messages property to the fake request # in order to make it compatible with MessageMiddleware. fake_request._messages = mock.Mock() - member_ip_filter = self.get_member_ip_filter(member_ip) with self.assertRaises(IncorrectLookupParameters): - queryset = member_ip_filter.queryset( - fake_request, - Network.objects.all() - ) + member_ip_filter.queryset(fake_request, Network.objects.all()) diff --git a/src/ralph/networks/tests/test_forms.py b/src/ralph/networks/tests/test_forms.py index a165425ce3..60d8ff15c9 100755 --- a/src/ralph/networks/tests/test_forms.py +++ b/src/ralph/networks/tests/test_forms.py @@ -1,13 +1,13 @@ from django.contrib.auth import get_user_model from django.test import RequestFactory -from ralph.assets.models.components import Ethernet, EthernetSpeed +from ralph.assets.models.components import Ethernet from ralph.data_center.tests.factories import DataCenterFactory from ralph.networks.models import IPAddress from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory + NetworkFactory, ) from ralph.tests import RalphTestCase from ralph.tests.models import PolymorphicTestModel @@ -15,92 +15,86 @@ class NetworkInlineTestCase(RalphTestCase): def setUp(self): - self.inline_prefix = 'ethernet_set-' - self.obj1 = PolymorphicTestModel.objects.create(hostname='abc') - self.obj2 = PolymorphicTestModel.objects.create(hostname='xyz') + self.inline_prefix = "ethernet_set-" + self.obj1 = PolymorphicTestModel.objects.create(hostname="abc") + self.obj2 = PolymorphicTestModel.objects.create(hostname="xyz") self.ip1 = IPAddressFactory( ethernet__base_object=self.obj1, - address='127.0.0.1', + address="127.0.0.1", is_management=True, ) self.ip2 = IPAddressFactory( ethernet__base_object=self.obj2, - address='127.1.0.1', + address="127.1.0.1", is_management=True, ) self.eth1 = self.ip1.ethernet self.user = get_user_model().objects.create_superuser( - username='root', - password='password', - email='email@email.pl' + username="root", password="password", email="email@email.pl" ) - result = self.client.login(username='root', password='password') + result = self.client.login(username="root", password="password") self.assertEqual(result, True) self.factory = RequestFactory() def _prepare_inline_data(self, d): - return { - '{}{}'.format(self.inline_prefix, k): v for (k, v) in d.items() - } + return {"{}{}".format(self.inline_prefix, k): v for (k, v) in d.items()} def test_adding_new_record_should_pass(self): inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-base_object': self.obj1.id, - '1-hostname': 'def', - '1-address': '127.0.0.2', - '1-mac': '10:20:30:40:50:60', - '1-label': 'eth1', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-base_object": self.obj1.id, + "1-hostname": "def", + "1-address": "127.0.0.2", + "1-mac": "10:20:30:40:50:60", + "1-label": "eth1", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 302) - ip = IPAddress.objects.get(address='127.0.0.2') - self.assertEqual(ip.hostname, 'def') + ip = IPAddress.objects.get(address="127.0.0.2") + self.assertEqual(ip.hostname, "def") self.assertFalse(ip.is_management) self.assertFalse(ip.dhcp_expose) - self.assertEqual(ip.ethernet.mac, '10:20:30:40:50:60') - self.assertEqual(ip.ethernet.label, 'eth1') + self.assertEqual(ip.ethernet.mac, "10:20:30:40:50:60") + self.assertEqual(ip.ethernet.label, "eth1") self.assertEqual(ip.ethernet.base_object.pk, self.obj1.pk) def test_adding_new_record_without_ip_and_hostname_should_pass(self): inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-base_object': self.obj1.id, - '1-mac': '10:20:30:40:50:60', - '1-label': 'eth1', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-base_object": self.obj1.id, + "1-mac": "10:20:30:40:50:60", + "1-label": "eth1", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 302) - eth = Ethernet.objects.get(mac='10:20:30:40:50:60') - self.assertEqual(eth.label, 'eth1') + eth = Ethernet.objects.get(mac="10:20:30:40:50:60") + self.assertEqual(eth.label, "eth1") self.assertEqual(eth.base_object.pk, self.obj1.pk) # ip should not be created with self.assertRaises(IPAddress.DoesNotExist): @@ -108,29 +102,28 @@ def test_adding_new_record_without_ip_and_hostname_should_pass(self): def test_adding_new_record_without_mac_should_pass(self): inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-base_object': self.obj1.id, - '1-hostname': 'def', - '1-address': '127.0.0.2', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-base_object": self.obj1.id, + "1-hostname": "def", + "1-address": "127.0.0.2", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 302) - ip = IPAddress.objects.get(address='127.0.0.2') - self.assertEqual(ip.hostname, 'def') + ip = IPAddress.objects.get(address="127.0.0.2") + self.assertEqual(ip.hostname, "def") self.assertFalse(ip.is_management) self.assertFalse(ip.dhcp_expose) self.assertFalse(bool(ip.ethernet.mac)) # mac is either None or '' @@ -140,27 +133,25 @@ def test_adding_new_record_without_mac_should_pass(self): def test_adding_multiple_new_record_without_mac_should_pass(self): # test for storing mac as null inline_data = { - 'TOTAL_FORMS': 3, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-base_object': self.obj1.id, - '1-hostname': 'def', - '1-address': '127.0.0.2', - - '2-base_object': self.obj1.id, - '2-hostname': 'def', - '2-address': '127.0.0.3', + "TOTAL_FORMS": 3, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-base_object": self.obj1.id, + "1-hostname": "def", + "1-address": "127.0.0.2", + "2-base_object": self.obj1.id, + "2-hostname": "def", + "2-address": "127.0.0.3", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) @@ -168,549 +159,496 @@ def test_adding_multiple_new_record_without_mac_should_pass(self): def test_adding_new_record_without_mac_and_ip_should_not_pass(self): inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-base_object': self.obj1.id, - '1-label': 'eth1', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-base_object": self.obj1.id, + "1-label": "eth1", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - for err in response.context_data['errors']: - self.assertIn('At least one of mac, address is required', err) + for err in response.context_data["errors"]: + self.assertIn("At least one of mac, address is required", err) def test_adding_new_record_with_existing_ip_should_not_pass(self): inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-base_object': self.obj1.id, - '1-hostname': 'def', - '1-mac': '11:12:13:14:15:16', - '1-address': self.ip2.address, # duplicated ip! + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-base_object": self.obj1.id, + "1-hostname": "def", + "1-mac": "11:12:13:14:15:16", + "1-address": self.ip2.address, # duplicated ip! } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Address {} already exist.'.format(self.ip2.address) - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Address {} already exist.".format(self.ip2.address) + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_more_than_one_ip_is_management(self): inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-hostname': 'def', - '1-base_object': self.obj1.id, - '1-address': '127.0.0.2', - '1-mac': '', - '1-label': '', - '1-is_management': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-hostname": "def", + "1-base_object": self.obj1.id, + "1-address": "127.0.0.2", + "1-mac": "", + "1-label": "", + "1-is_management": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) self.assertIn( - 'Only one management IP address can be assigned to this asset', - response.context_data['errors'] + "Only one management IP address can be assigned to this asset", + response.context_data["errors"], ) def test_empty_address_and_not_empty_hostname_should_not_pass(self): inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-hostname': self.ip1.hostname, - '0-address': self.ip1.address, - '0-mac': self.eth1.mac, - '0-label': '', - '0-is_management': 'on', - - '1-hostname': 'def', - '1-base_object': self.obj1.id, - '1-address': '', - '1-mac': '10:20:30:40:50:60', - '1-label': '', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-hostname": self.ip1.hostname, + "0-address": self.ip1.address, + "0-mac": self.eth1.mac, + "0-label": "", + "0-is_management": "on", + "1-hostname": "def", + "1-base_object": self.obj1.id, + "1-address": "", + "1-mac": "10:20:30:40:50:60", + "1-label": "", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) msg = ( - 'Address is required when one of hostname, is_management, ' - 'dhcp_expose is filled' - ) - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) + "Address is required when one of hostname, is_management, " + "dhcp_expose is filled" ) + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) class NetworkInlineWithDHCPExposeTestCase(RalphTestCase): def setUp(self): - self.inline_prefix = 'ethernet_set-' - self.obj1 = PolymorphicTestModel.objects.create(hostname='abc') + self.inline_prefix = "ethernet_set-" + self.obj1 = PolymorphicTestModel.objects.create(hostname="abc") self.ip1 = IPAddressFactory( ethernet__base_object=self.obj1, - ethernet__mac='10:20:30:40:50:60', - hostname='s11.dc.local', - address='127.0.0.1', + ethernet__mac="10:20:30:40:50:60", + hostname="s11.dc.local", + address="127.0.0.1", is_management=True, ) self.eth1 = self.ip1.ethernet self.user = get_user_model().objects.create_superuser( - username='root', - password='password', - email='email@email.pl' + username="root", password="password", email="email@email.pl" ) - result = self.client.login(username='root', password='password') + result = self.client.login(username="root", password="password") self.assertEqual(result, True) self.factory = RequestFactory() def _prepare_inline_data(self, d): - return { - '{}{}'.format(self.inline_prefix, k): v for (k, v) in d.items() - } + return {"{}{}".format(self.inline_prefix, k): v for (k, v) in d.items()} def test_dhcp_expose_readonly_fields_should_not_change_their_value(self): self.ip1.dhcp_expose = True self.ip1.save() inline_data = { - 'TOTAL_FORMS': 1, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eth10', + "TOTAL_FORMS": 1, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eth10", # readonly fields modification! - '0-hostname': 's222.dc.local', - '0-address': '127.1.1.1', - '0-mac': '11:11:11:11:11:11', + "0-hostname": "s222.dc.local", + "0-address": "127.1.1.1", + "0-mac": "11:11:11:11:11:11", # notice missing dhcp_expose field } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 302) # besides 302, readonly fields are untouched self.ip1.refresh_from_db() - self.assertEqual(self.ip1.address, '127.0.0.1') - self.assertEqual(self.ip1.hostname, 's11.dc.local') + self.assertEqual(self.ip1.address, "127.0.0.1") + self.assertEqual(self.ip1.hostname, "s11.dc.local") self.assertEqual(self.ip1.dhcp_expose, True) self.eth1.refresh_from_db() - self.assertEqual(self.eth1.mac, '10:20:30:40:50:60') + self.assertEqual(self.eth1.mac, "10:20:30:40:50:60") # other fields could be changed - self.assertEqual(self.eth1.label, 'eth10') + self.assertEqual(self.eth1.label, "eth10") def test_dhcp_expose_delete_should_not_work(self): self.ip1.dhcp_expose = True self.ip1.save() inline_data = { - 'TOTAL_FORMS': 1, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eth10', - '0-hostname': 's222.dc.local', - '0-address': '127.1.1.1', - '0-mac': '11:11:11:11:11:11', - '0-DELETE': 'on', # deleting row with DHCP entry! + "TOTAL_FORMS": 1, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eth10", + "0-hostname": "s222.dc.local", + "0-address": "127.1.1.1", + "0-mac": "11:11:11:11:11:11", + "0-DELETE": "on", # deleting row with DHCP entry! } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Cannot delete entry if its exposed in DHCP' - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Cannot delete entry if its exposed in DHCP" + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_dhcp_expose_for_new_record_should_pass(self): self.ip1.dhcp_expose = True self.ip1.save() inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eth10', - - '1-base_object': self.obj1.id, - '1-hostname': 'def', - '1-address': '127.0.0.2', - '1-mac': '10:10:10:10:10:10', - '1-label': 'eth10', - '1-dhcp_expose': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eth10", + "1-base_object": self.obj1.id, + "1-hostname": "def", + "1-address": "127.0.0.2", + "1-mac": "10:10:10:10:10:10", + "1-label": "eth10", + "1-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 302) - ip = IPAddress.objects.get(address='127.0.0.2') - self.assertEqual(ip.hostname, 'def') + ip = IPAddress.objects.get(address="127.0.0.2") + self.assertEqual(ip.hostname, "def") self.assertTrue(ip.dhcp_expose) - self.assertEqual(ip.ethernet.mac, '10:10:10:10:10:10') - self.assertEqual(ip.ethernet.label, 'eth10') + self.assertEqual(ip.ethernet.mac, "10:10:10:10:10:10") + self.assertEqual(ip.ethernet.label, "eth10") self.assertEqual(ip.ethernet.base_object.pk, self.obj1.pk) - def test_dhcp_expose_for_new_record_duplicate_hostname_should_not_pass(self): # noqa + def test_dhcp_expose_for_new_record_duplicate_hostname_should_not_pass(self): # noqa network = NetworkFactory( - address='127.0.0.0/24', + address="127.0.0.0/24", network_environment=NetworkEnvironmentFactory( - data_center=DataCenterFactory( - name='DC1' - ) - ) + data_center=DataCenterFactory(name="DC1") + ), ) self.test_dhcp_expose_for_new_record_should_pass() # generate duplicate - obj2 = PolymorphicTestModel.objects.create(hostname='xyz') + obj2 = PolymorphicTestModel.objects.create(hostname="xyz") inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': obj2.id, - '0-mac': 'ff:ff:ff:ff:ff:ff', - '0-label': 'eth10', - - '1-base_object': obj2.id, - '1-hostname': self.ip1.hostname, - '1-address': '127.0.0.3', - '1-mac': '11:11:11:11:11:11', - '1-label': 'eth10', - '1-dhcp_expose': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": obj2.id, + "0-mac": "ff:ff:ff:ff:ff:ff", + "0-label": "eth10", + "1-base_object": obj2.id, + "1-hostname": self.ip1.hostname, + "1-address": "127.0.0.3", + "1-mac": "11:11:11:11:11:11", + "1-label": "eth10", + "1-dhcp_expose": "on", } data = { - 'hostname': obj2.hostname, - 'id': obj2.id, + "hostname": obj2.hostname, + "id": obj2.id, } data.update(self._prepare_inline_data(inline_data)) - response = self.client.post( - obj2.get_absolute_url(), - data, - follow=True - ) + response = self.client.post(obj2.get_absolute_url(), data, follow=True) self.assertEqual(response.status_code, 200) - msg = 'Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( # noqa - hostname=self.ip1.hostname, - dc=network.network_environment.data_center - ) - self.assertIn('errors', response.context_data) - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) + msg = 'Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( # noqa + hostname=self.ip1.hostname, dc=network.network_environment.data_center ) + self.assertIn("errors", response.context_data) + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) - def test_dhcp_expose_for_existing_record_duplicate_hostname_should_not_pass(self): # noqa + def test_dhcp_expose_for_existing_record_duplicate_hostname_should_not_pass(self): # noqa network = NetworkFactory( - address='192.168.0.0/24', + address="192.168.0.0/24", network_environment=NetworkEnvironmentFactory( - data_center=DataCenterFactory( - name='DC1' - ) - ) + data_center=DataCenterFactory(name="DC1") + ), ) - name = 'some.hostname' - ip = IPAddressFactory( - dhcp_expose=True, - hostname=name, - address='192.168.0.7' + name = "some.hostname" + IPAddressFactory( + dhcp_expose=True, hostname=name, address="192.168.0.7" ).save() self.ip1.hostname = name - self.ip1.address = '192.168.0.12' + self.ip1.address = "192.168.0.12" self.ip1.save() inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eth10', - - '1-base_object': self.obj1.id, - '1-hostname': name, - '1-address': '192.168.0.33', - '1-mac': '10:10:10:10:10:10', - '1-label': 'eth10', - '1-dhcp_expose': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eth10", + "1-base_object": self.obj1.id, + "1-hostname": name, + "1-address": "192.168.0.33", + "1-mac": "10:10:10:10:10:10", + "1-label": "eth10", + "1-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) - response = self.client.post( - self.obj1.get_absolute_url(), - data, - follow=True - ) - msg = 'Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( # noqa - hostname=self.ip1.hostname, - dc=network.network_environment.data_center - ) - self.assertIn('errors', response.context_data) - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) + response = self.client.post(self.obj1.get_absolute_url(), data, follow=True) + msg = 'Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( # noqa + hostname=self.ip1.hostname, dc=network.network_environment.data_center ) + self.assertIn("errors", response.context_data) + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_dhcp_expose_for_existing_record_should_pass(self): inline_data = { - 'TOTAL_FORMS': 1, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eth10', - '0-hostname': 's11.dc.local', - '0-address': '127.0.0.1', - '0-mac': '10:20:30:40:50:60', - '0-dhcp_expose': 'on', + "TOTAL_FORMS": 1, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eth10", + "0-hostname": "s11.dc.local", + "0-address": "127.0.0.1", + "0-mac": "10:20:30:40:50:60", + "0-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 302) - ip = IPAddress.objects.get(address='127.0.0.1') - self.assertEqual(ip.hostname, 's11.dc.local') + ip = IPAddress.objects.get(address="127.0.0.1") + self.assertEqual(ip.hostname, "s11.dc.local") self.assertTrue(ip.dhcp_expose) - self.assertEqual(ip.ethernet.mac, '10:20:30:40:50:60') - self.assertEqual(ip.ethernet.label, 'eth10') + self.assertEqual(ip.ethernet.mac, "10:20:30:40:50:60") + self.assertEqual(ip.ethernet.label, "eth10") self.assertEqual(ip.ethernet.base_object.pk, self.obj1.pk) def test_dhcp_expose_without_address_for_new_record_should_not_pass(self): self.ip1.dhcp_expose = True self.ip1.save() inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eht10', - - '1-base_object': self.obj1.id, - '1-hostname': '', - '1-address': '', - '1-mac': '10:10:10:10:10:10', - '1-label': 'eth10', - '1-dhcp_expose': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eht10", + "1-base_object": self.obj1.id, + "1-hostname": "", + "1-address": "", + "1-mac": "10:10:10:10:10:10", + "1-label": "eth10", + "1-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Cannot expose in DHCP without IP address' - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Cannot expose in DHCP without IP address" + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_dhcp_expose_with_address_exist_for_new_record_should_not_pass(self): self.ip1.dhcp_expose = True self.ip1.save() inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eht10', - - '1-base_object': self.obj1.id, - '1-hostname': '', - '1-address': self.ip1.address, - '1-mac': '10:10:10:10:10:10', - '1-label': 'eth10', - '1-dhcp_expose': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eht10", + "1-base_object": self.obj1.id, + "1-hostname": "", + "1-address": self.ip1.address, + "1-mac": "10:10:10:10:10:10", + "1-label": "eth10", + "1-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) error_messages = [ - 'Cannot expose in DHCP without IP address', - 'Address {} already exist.'.format(self.ip1.address) + "Cannot expose in DHCP without IP address", + "Address {} already exist.".format(self.ip1.address), ] for msg in error_messages: self.assertTrue( - any([msg in err for err in response.context_data['errors']]) + any([msg in err for err in response.context_data["errors"]]) ) def test_dhcp_expose_without_mac_for_new_record_should_not_pass(self): self.ip1.dhcp_expose = True self.ip1.save() inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eht10', - - '1-base_object': self.obj1.id, - '1-hostname': 'def', - '1-address': '127.0.0.2', - '1-mac': '', - '1-label': 'eth10', - '1-dhcp_expose': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eht10", + "1-base_object": self.obj1.id, + "1-hostname": "def", + "1-address": "127.0.0.2", + "1-mac": "", + "1-label": "eth10", + "1-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Cannot expose in DHCP without MAC address' - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Cannot expose in DHCP without MAC address" + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_dhcp_expose_without_hostname_for_new_record_should_not_pass(self): self.ip1.dhcp_expose = True self.ip1.save() inline_data = { - 'TOTAL_FORMS': 2, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eht10', - - '1-base_object': self.obj1.id, - '1-hostname': '', - '1-address': '127.0.0.2', - '1-mac': '10:10:10:10:10:10', - '1-label': 'eth10', - '1-dhcp_expose': 'on', + "TOTAL_FORMS": 2, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eht10", + "1-base_object": self.obj1.id, + "1-hostname": "", + "1-address": "127.0.0.2", + "1-mac": "10:10:10:10:10:10", + "1-label": "eth10", + "1-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Cannot expose in DHCP without hostname' - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Cannot expose in DHCP without hostname" + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_dhcp_expose_without_address_for_existing_record_should_not_pass(self): # noqa inline_data = { - 'TOTAL_FORMS': 1, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eht10', - '0-hostname': '', - '0-address': '', - '0-mac': '10:10:10:10:10:10', - '0-dhcp_expose': 'on', + "TOTAL_FORMS": 1, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eht10", + "0-hostname": "", + "0-address": "", + "0-mac": "10:10:10:10:10:10", + "0-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Cannot expose in DHCP without IP address' - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Cannot expose in DHCP without IP address" + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_dhcp_expose_without_mac_for_existing_record_should_not_pass(self): inline_data = { - 'TOTAL_FORMS': 1, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eht10', - '0-hostname': 'def', - '0-address': '127.0.0.2', - '0-mac': '', - '0-dhcp_expose': 'on', + "TOTAL_FORMS": 1, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eht10", + "0-hostname": "def", + "0-address": "127.0.0.2", + "0-mac": "", + "0-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Cannot expose in DHCP without MAC address' - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Cannot expose in DHCP without MAC address" + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) def test_dhcp_expose_without_hostname_for_existing_record_should_not_pass(self): # noqa inline_data = { - 'TOTAL_FORMS': 1, - 'INITIAL_FORMS': 1, - '0-id': self.eth1.id, - '0-base_object': self.obj1.id, - '0-label': 'eht10', - '0-hostname': '', - '0-address': '127.0.0.2', - '0-mac': '10:10:10:10:10:10', - '0-dhcp_expose': 'on', + "TOTAL_FORMS": 1, + "INITIAL_FORMS": 1, + "0-id": self.eth1.id, + "0-base_object": self.obj1.id, + "0-label": "eht10", + "0-hostname": "", + "0-address": "127.0.0.2", + "0-mac": "10:10:10:10:10:10", + "0-dhcp_expose": "on", } data = { - 'hostname': self.obj1.hostname, - 'id': self.obj1.id, + "hostname": self.obj1.hostname, + "id": self.obj1.id, } data.update(self._prepare_inline_data(inline_data)) response = self.client.post(self.obj1.get_absolute_url(), data) self.assertEqual(response.status_code, 200) - msg = 'Cannot expose in DHCP without hostname' - self.assertTrue( - any([msg in err for err in response.context_data['errors']]) - ) + msg = "Cannot expose in DHCP without hostname" + self.assertTrue(any([msg in err for err in response.context_data["errors"]])) diff --git a/src/ralph/networks/tests/test_models.py b/src/ralph/networks/tests/test_models.py index dadc962833..046662e2b9 100644 --- a/src/ralph/networks/tests/test_models.py +++ b/src/ralph/networks/tests/test_models.py @@ -12,16 +12,15 @@ from ralph.data_center.tests.factories import ( ClusterFactory, DataCenterAssetFactory, - DataCenterFactory + DataCenterFactory, ) from ralph.networks.admin import NetworkAdmin from ralph.networks.filters import NetworkClassFilter -from ralph.networks.models.choices import IPAddressStatus from ralph.networks.models.networks import IPAddress, Network from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory + NetworkFactory, ) from ralph.tests import RalphTestCase from ralph.virtual.tests.factories import VirtualServerFactory @@ -31,64 +30,64 @@ class SimpleNetworkTest(RalphTestCase): def setUp(self): self.net1 = Network.objects.create( - name='net1', - address='192.168.0.0/16', + name="net1", + address="192.168.0.0/16", ) self.net2 = Network.objects.create( parent=self.net1, - name='net2', - address='192.168.0.0/17', + name="net2", + address="192.168.0.0/17", ) self.net3 = Network.objects.create( parent=self.net2, - name='net3', - address='192.168.128.0/17', + name="net3", + address="192.168.128.0/17", ) self.net4 = Network.objects.create( parent=self.net3, - name='net4', - address='192.168.133.0/24', + name="net4", + address="192.168.133.0/24", ) self.net5 = Network.objects.create( - name='net5', - address='192.169.133.0/24', + name="net5", + address="192.169.133.0/24", ) - self.ip1 = IPAddress(address='192.168.128.10') + self.ip1 = IPAddress(address="192.168.128.10") self.ip1.save() - self.ip2 = IPAddress(address='192.168.133.10') + self.ip2 = IPAddress(address="192.168.133.10") self.ip2.save() - self.ip3 = IPAddress(address='192.168.128.11') + self.ip3 = IPAddress(address="192.168.128.11") self.ip3.save() Network.objects.rebuild() @unpack @data( - ('net1', 16), - ('net2', 17), + ("net1", 16), + ("net2", 17), ) def test_get_netmask(self, net, netmask): self.assertEqual(getattr(self, net).netmask, netmask) @unpack @data( - ('net1', ['net2', 'net3', 'net4']), - ('net3', ['net4']), + ("net1", ["net2", "net3", "net4"]), + ("net3", ["net4"]), ) def test_get_subnetworks(self, net, correct): net_obj = getattr(self, net) res = Network.objects.get(pk=net_obj.pk).get_subnetworks() - self.assertEqual( - list(res), list(Network.objects.filter(name__in=correct)) - ) + self.assertEqual(list(res), list(Network.objects.filter(name__in=correct))) def test_subnetworks_count_cast_to_integer(self): - net = Network.objects.get(pk=self.net1.pk) - count = Network.objects.filter(id=self.net1.id).annotate( - subnetworks_count=( - CastToInteger(F('rght')) - CastToInteger(F('lft')) + Network.objects.get(pk=self.net1.pk) + count = ( + Network.objects.filter(id=self.net1.id) + .annotate( + subnetworks_count=(CastToInteger(F("rght")) - CastToInteger(F("lft"))) ) - ).values_list('subnetworks_count', flat=True)[0] + .values_list("subnetworks_count", flat=True)[0] + ) self.assertTrue(count) @@ -96,8 +95,8 @@ def test_subnetworks_count_cast_to_integer(self): class NetworkTest(RalphTestCase): @unpack @data( - ('92.143.123.123', True), - ('10.168.123.123', False), + ("92.143.123.123", True), + ("10.168.123.123", False), ) def test_ip_is_public_or_no(self, ip, is_public): new_ip_address = IPAddress(address=ip) @@ -106,38 +105,38 @@ def test_ip_is_public_or_no(self, ip, is_public): @unpack @data( - ('::/128',), - ('::1/128',), - ('::/96',), - ('::ffff:0:0/64',), - ('2001:7f8::/32',), - ('2001:db8::/32',), - ('2002::/24',), - ('3ffe::/16',), - ('fd00::/7',), - ('fe80::/10',), - ('fec0::/10',), - ('ff00::/8',), + ("::/128",), + ("::1/128",), + ("::/96",), + ("::ffff:0:0/64",), + ("2001:7f8::/32",), + ("2001:db8::/32",), + ("2002::/24",), + ("3ffe::/16",), + ("fd00::/7",), + ("fe80::/10",), + ("fec0::/10",), + ("ff00::/8",), ) def test_network_should_support_ipv6(self, net): network = Network( - name='ipv6 ready', + name="ipv6 ready", address=net, ) self.assertEqual(network.network, ip_network(net, strict=False)) @unpack @data( - ('192.168.100.0/24', '192.168.100.1', True), - ('10.1.1.0/24', '10.1.1.1', True), - ('10.1.1.0/24', '10.1.1.2', True), - ('10.1.1.0/31', '10.1.1.2', False), - ('10.1.1.0/31', '10.1.1.1', True), - ('10.1.1.0/31', '10.1.1.0', True), + ("192.168.100.0/24", "192.168.100.1", True), + ("10.1.1.0/24", "10.1.1.1", True), + ("10.1.1.0/24", "10.1.1.2", True), + ("10.1.1.0/31", "10.1.1.2", False), + ("10.1.1.0/31", "10.1.1.1", True), + ("10.1.1.0/31", "10.1.1.0", True), ) def test_ip_address_should_return_network(self, network, ip, should_return): net = Network.objects.create( - name='ip_address_should_return_network', + name="ip_address_should_return_network", address=network, ) ip = IPAddress.objects.create(address=ip) @@ -149,12 +148,12 @@ def test_ip_address_should_return_network(self, network, ip, should_return): @unpack @data( - ('10.1.1.0/24', '10.1.0.255'), - ('10.1.1.0/24', '10.1.2.0'), + ("10.1.1.0/24", "10.1.0.255"), + ("10.1.1.0/24", "10.1.2.0"), ) def test_ip_address_should_not_return_network(self, network, ip): Network.objects.create( - name='ip_address_should_return_network', + name="ip_address_should_return_network", address=network, ) ip = IPAddress.objects.create(address=ip, network=None) @@ -163,16 +162,16 @@ def test_ip_address_should_not_return_network(self, network, ip): def test_create_ip_address(self): Network.objects.create( - name='test_create_ip_address', - address='10.1.1.0/24', + name="test_create_ip_address", + address="10.1.1.0/24", ) - IPAddress.objects.create(address='10.1.1.0') + IPAddress.objects.create(address="10.1.1.0") @unpack @data( - ('192.168.1.0/24', 254), - ('192.168.1.0/30', 2), - ('192.168.1.0/31', 2), + ("192.168.1.0/24", 254), + ("192.168.1.0/30", 2), + ("192.168.1.0/31", 2), ) def test_net_size(self, addr, size): net = Network.objects.create(address=addr) @@ -180,9 +179,9 @@ def test_net_size(self, addr, size): @unpack @data( - ('192.168.1.0/29', ip_address('192.168.1.1'), []), - ('192.168.1.0/31', None, []), - ('192.168.1.0/29', ip_address('192.168.1.2'), ['192.168.1.1']), + ("192.168.1.0/29", ip_address("192.168.1.1"), []), + ("192.168.1.0/31", None, []), + ("192.168.1.0/29", ip_address("192.168.1.2"), ["192.168.1.1"]), ) def test_get_first_free_ip(self, network_addr, first_free, used): net = Network.objects.create( @@ -197,12 +196,16 @@ def test_get_first_free_ip(self, network_addr, first_free, used): @unpack @data( - ('192.168.1.0/24', ip_address('192.168.1.11'), 10, 10, []), - ('192.168.1.0/24', ip_address('192.168.1.13'), 10, 10, [ - '192.168.1.11', '192.168.1.12' - ]), - ('192.168.1.0/24', None, 127, 127, []), - ('192.168.1.0/30', None, 0, 0, ['192.168.1.1', '192.168.1.2']), + ("192.168.1.0/24", ip_address("192.168.1.11"), 10, 10, []), + ( + "192.168.1.0/24", + ip_address("192.168.1.13"), + 10, + 10, + ["192.168.1.11", "192.168.1.12"], + ), + ("192.168.1.0/24", None, 127, 127, []), + ("192.168.1.0/30", None, 0, 0, ["192.168.1.1", "192.168.1.2"]), ) def test_get_first_free_ip_with_reserved( self, network_addr, first_free, reserved_beggining, reserved_end, used @@ -218,20 +221,25 @@ def test_get_first_free_ip_with_reserved( @unpack @data( - ('192.168.1.0/30', True, ['192.168.1.1', '192.168.1.2'], None), - ('192.168.1.0/30', True, ['192.168.1.1'], ip_address('192.168.1.2')), - ('192.168.1.0/30', False, ['192.168.1.1', '192.168.1.2'], ip_address('192.168.1.1')), # noqa + ("192.168.1.0/30", True, ["192.168.1.1", "192.168.1.2"], None), + ("192.168.1.0/30", True, ["192.168.1.1"], ip_address("192.168.1.2")), + ( + "192.168.1.0/30", + False, + ["192.168.1.1", "192.168.1.2"], + ip_address("192.168.1.1"), + ), # noqa ) def test_get_first_free_ip_respect_DNSaaS( self, network_addr, dnsaas_enabled, records, first_free ): - def is_in_dnsaas_mocked(ip): if not dnsaas_enabled: return False return str(ip) in records + patcher = patch( - 'ralph.networks.models.networks.is_in_dnsaas', is_in_dnsaas_mocked + "ralph.networks.models.networks.is_in_dnsaas", is_in_dnsaas_mocked ) net = Network.objects.create( address=network_addr, @@ -244,48 +252,32 @@ def is_in_dnsaas_mocked(ip): patcher.stop() def test_min_and_max_ip_are_assigned(self): - net = Network.objects.create( - name='net', address='1.0.0.0/16' - ) + net = Network.objects.create(name="net", address="1.0.0.0/16") self.assertEqual(net.min_ip, 16777216) # 1.0.0.0 self.assertEqual(net.max_ip, 16842751) # 1.0.255.255 def test_sub_network_should_assign_automatically(self): - net = Network.objects.create( - name='net', address='192.168.5.0/24' - ) - subnet = Network.objects.create( - name='subnet', address='192.168.5.0/25' - ) + net = Network.objects.create(name="net", address="192.168.5.0/24") + subnet = Network.objects.create(name="subnet", address="192.168.5.0/25") self.assertEqual(net, subnet.parent) def test_sub_network_should_change_automatically(self): - net1 = Network.objects.create( - name='net', address='10.20.30.0/24' - ) - net2 = Network.objects.create( - name='net2', address='10.20.30.240/28' - ) + net1 = Network.objects.create(name="net", address="10.20.30.0/24") + net2 = Network.objects.create(name="net2", address="10.20.30.240/28") self.assertEqual(net1, net2.parent) - net3 = Network.objects.create( - name='net3', address='10.20.30.128/25' - ) + net3 = Network.objects.create(name="net3", address="10.20.30.128/25") self.refresh_objects_from_db(net2, net3) self.assertEqual(net2.parent, net3) self.assertIn(net2, net3.get_immediate_subnetworks()) self.assertEqual(net3.parent, net1) - net4 = Network.objects.create( - name='net4', address='10.20.40.128/28' - ) - net5 = Network.objects.create( - name='net5', address='10.20.40.0/24' - ) - net3.address = '10.20.40.128/25' + net4 = Network.objects.create(name="net4", address="10.20.40.128/28") + net5 = Network.objects.create(name="net5", address="10.20.40.0/24") + net3.address = "10.20.40.128/25" net3.save() self.refresh_objects_from_db(net1, net2, net3, net4, net5) @@ -299,27 +291,19 @@ def test_sub_network_should_change_automatically(self): self.assertEqual(net4.parent, net5) def test_sub_network_should_reassign_ip(self): - ip = IPAddress.objects.create(address='192.169.58.1') + ip = IPAddress.objects.create(address="192.169.58.1") self.assertEqual(ip.network, None) - net = Network.objects.create( - name='net', address='192.169.58.0/24' - ) - sub1 = Network.objects.create( - name='sub_net1', address='192.169.58.0/25' - ) - sub2 = Network.objects.create( - name='sub_net2', address='192.169.58.128/26' - ) + net = Network.objects.create(name="net", address="192.169.58.0/24") + sub1 = Network.objects.create(name="sub_net1", address="192.169.58.0/25") + sub2 = Network.objects.create(name="sub_net2", address="192.169.58.128/26") self.refresh_objects_from_db(net) net.save() self.refresh_objects_from_db(ip, sub1, sub2) self.assertEqual(ip.network, sub1) def test_delete_network_shouldnt_delete_related_ip(self): - net = Network.objects.create( - name='net', address='192.169.58.0/24' - ) - ip = IPAddress.objects.create(address='192.169.58.1', network=net) + net = Network.objects.create(name="net", address="192.169.58.0/24") + ip = IPAddress.objects.create(address="192.169.58.1", network=net) net.delete() ip.refresh_from_db() self.assertTrue(ip) @@ -328,130 +312,125 @@ def test_delete_network_shouldnt_delete_related_ip(self): class NetworkEnvironmentTest(RalphTestCase): def test_issue_next_hostname(self): ne = NetworkEnvironmentFactory( - hostname_template_prefix='s123', - hostname_template_postfix='.dc.local', + hostname_template_prefix="s123", + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, ) ne2 = NetworkEnvironmentFactory( # same params as ne - hostname_template_prefix='s123', - hostname_template_postfix='.dc.local', + hostname_template_prefix="s123", + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, ) ne3 = NetworkEnvironmentFactory( # other params comparing to ne - hostname_template_prefix='s1', - hostname_template_postfix='.dc.local', + hostname_template_prefix="s1", + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, ) - self.assertEqual(ne.issue_next_free_hostname(), 's12300001.dc.local') - self.assertEqual(ne.issue_next_free_hostname(), 's12300002.dc.local') - self.assertEqual(ne.issue_next_free_hostname(), 's12300003.dc.local') - self.assertEqual(ne2.issue_next_free_hostname(), 's12300004.dc.local') - self.assertEqual(ne.issue_next_free_hostname(), 's12300005.dc.local') - self.assertEqual(ne3.issue_next_free_hostname(), 's100001.dc.local') + self.assertEqual(ne.issue_next_free_hostname(), "s12300001.dc.local") + self.assertEqual(ne.issue_next_free_hostname(), "s12300002.dc.local") + self.assertEqual(ne.issue_next_free_hostname(), "s12300003.dc.local") + self.assertEqual(ne2.issue_next_free_hostname(), "s12300004.dc.local") + self.assertEqual(ne.issue_next_free_hostname(), "s12300005.dc.local") + self.assertEqual(ne3.issue_next_free_hostname(), "s100001.dc.local") def test_issue_next_hostname_when_a_few_next_hostnames_are_taken(self): hostname_model_factories = [ - ClusterFactory, - DataCenterAssetFactory, - IPAddressFactory, - VirtualServerFactory, + ClusterFactory, + DataCenterAssetFactory, + IPAddressFactory, + VirtualServerFactory, ] for i, model_factory in enumerate(hostname_model_factories): - model_factory(hostname='s1230000{}.dc.local'.format(i)) + model_factory(hostname="s1230000{}.dc.local".format(i)) ne = NetworkEnvironmentFactory( - hostname_template_prefix='s123', - hostname_template_postfix='.dc.local', + hostname_template_prefix="s123", + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, ) self.assertEqual( ne.issue_next_free_hostname(), - 's1230000{}.dc.local'.format(len(hostname_model_factories)) + "s1230000{}.dc.local".format(len(hostname_model_factories)), ) def test_issue_next_hostname_overflow(self): - alhg = AssetLastHostname.objects.create( - prefix='s123', - postfix='.dc.local', + AssetLastHostname.objects.create( + prefix="s123", + postfix=".dc.local", counter=99998, ) ne = NetworkEnvironmentFactory( - hostname_template_prefix='s123', - hostname_template_postfix='.dc.local', + hostname_template_prefix="s123", + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, ) - self.assertEqual(ne.issue_next_free_hostname(), 's12399999.dc.local') - self.assertEqual(ne.issue_next_free_hostname(), 's123100000.dc.local') + self.assertEqual(ne.issue_next_free_hostname(), "s12399999.dc.local") + self.assertEqual(ne.issue_next_free_hostname(), "s123100000.dc.local") def test_get_next_hostname(self): ne = NetworkEnvironmentFactory( - hostname_template_prefix='s123', - hostname_template_postfix='.dc.local', + hostname_template_prefix="s123", + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, ) # check if hostname is not increased - self.assertEqual(ne.next_free_hostname, 's12300001.dc.local') - self.assertEqual(ne.next_free_hostname, 's12300001.dc.local') + self.assertEqual(ne.next_free_hostname, "s12300001.dc.local") + self.assertEqual(ne.next_free_hostname, "s12300001.dc.local") def test_get_next_hostname_considers_other_models(self): hostname_model_factories = [ - ClusterFactory, - DataCenterAssetFactory, - IPAddressFactory, - VirtualServerFactory, + ClusterFactory, + DataCenterAssetFactory, + IPAddressFactory, + VirtualServerFactory, ] for i, model_factory in enumerate(hostname_model_factories): - model_factory(hostname='s1230000{}.dc.local'.format(i)) + model_factory(hostname="s1230000{}.dc.local".format(i)) ne = NetworkEnvironmentFactory( - hostname_template_prefix='s123', - hostname_template_postfix='.dc.local', + hostname_template_prefix="s123", + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, ) - expected_hostname = 's1230000{}.dc.local'.format( - len(hostname_model_factories) - ) + expected_hostname = "s1230000{}.dc.local".format(len(hostname_model_factories)) # check if hostname is not increased self.assertEqual(ne.next_free_hostname, expected_hostname) self.assertEqual(ne.next_free_hostname, expected_hostname) def test_next_hostname_without_counter(self): - prefix = 'test.' - postfix = '.ralph.pl' + prefix = "test." + postfix = ".ralph.pl" network_env = NetworkEnvironmentFactory( hostname_template_prefix=prefix, hostname_template_postfix=postfix, hostname_template_counter_length=6, - use_hostname_counter=False + use_hostname_counter=False, ) self.assertEqual( - network_env.next_hostname_without_model_counter(), - 'test.000001.ralph.pl' + network_env.next_hostname_without_model_counter(), "test.000001.ralph.pl" ) - for i in ['000009', '000001', '000008', '000007', '000050', '000044']: + for i in ["000009", "000001", "000008", "000007", "000050", "000044"]: DataCenterAssetFactory(hostname="".join([prefix, i, postfix])) self.assertEqual( - network_env.next_hostname_without_model_counter(), - 'test.000051.ralph.pl' + network_env.next_hostname_without_model_counter(), "test.000051.ralph.pl" ) - for i in ['000019', '000011', '000098', '000053', '000444']: + for i in ["000019", "000011", "000098", "000053", "000444"]: VirtualServerFactory(hostname="".join([prefix, i, postfix])) self.assertEqual( - network_env.next_hostname_without_model_counter(), - 'test.000445.ralph.pl' + network_env.next_hostname_without_model_counter(), "test.000445.ralph.pl" ) def test_use_hostname_counter_updates_last_hostname_counter(self): - prefix = 'test.' - postfix = '.ralph.pl' + prefix = "test." + postfix = ".ralph.pl" network_env = NetworkEnvironmentFactory( hostname_template_prefix=prefix, hostname_template_postfix=postfix, @@ -459,10 +438,8 @@ def test_use_hostname_counter_updates_last_hostname_counter(self): use_hostname_counter=False, ) current = 10 - DataCenterAssetFactory(hostname="".join([ - prefix, str(current), postfix - ])) - ok_next_hostname = 'test.{host_num:0{fill}}.ralph.pl'.format( + DataCenterAssetFactory(hostname="".join([prefix, str(current), postfix])) + ok_next_hostname = "test.{host_num:0{fill}}.ralph.pl".format( host_num=current + 1, fill=network_env.hostname_template_counter_length, ) @@ -475,18 +452,18 @@ def test_use_hostname_counter_updates_last_hostname_counter(self): self.assertEqual(network_env.next_free_hostname, ok_next_hostname) def test_should_pass_non_integer_counter(self): - prefix = 't4' - postfix = '.dc.local' - non_integer_counter = 'non-integer-counter' + prefix = "t4" + postfix = ".dc.local" + non_integer_counter = "non-integer-counter" ne = NetworkEnvironmentFactory( hostname_template_prefix=prefix, - hostname_template_postfix='.dc.local', + hostname_template_postfix=".dc.local", hostname_template_counter_length=5, - use_hostname_counter=True + use_hostname_counter=True, + ) + DataCenterAssetFactory( + hostname="".join([prefix, non_integer_counter, postfix]) ) - dc_asset = DataCenterAssetFactory(hostname=''.join([ - prefix, non_integer_counter, postfix - ])) self.assertEqual(ne.current_counter_without_model(), 0) @@ -516,8 +493,7 @@ def test_clear_hostname_with_dhcp_exposition_should_not_pass(self): self.ip.save() self.ip.hostname = None with self.assertRaises( - ValidationError, - msg='Cannot expose in DHCP without hostname' + ValidationError, msg="Cannot expose in DHCP without hostname" ): self.ip.clean() @@ -532,8 +508,7 @@ def test_clear_mac_address_with_ip_with_dhcp_exposition_should_not_pass(self): self.ip.ethernet.save() self.ip.dhcp_expose = True with self.assertRaises( - ValidationError, - msg='Cannot expose in DHCP without MAC address' + ValidationError, msg="Cannot expose in DHCP without MAC address" ): self.ip.clean() @@ -542,28 +517,25 @@ def test_detach_ethernet_with_dhcp_exposition_should_not_pass(self): # noqa self.ip.save() self.ip.dhcp_expose = True with self.assertRaises( - ValidationError, - msg='Cannot expose in DHCP without MAC address' + ValidationError, msg="Cannot expose in DHCP without MAC address" ): self.ip.clean() def test_change_hostname_with_dhcp_exposition_should_not_pass(self): # noqa self.ip.dhcp_expose = True self.ip.save() - self.ip.hostname = 'another-hostname' + self.ip.hostname = "another-hostname" with self.assertRaises( - ValidationError, - msg='Cannot change hostname when exposing in DHCP' + ValidationError, msg="Cannot change hostname when exposing in DHCP" ): self.ip.clean() def test_change_address_with_dhcp_exposition_should_not_pass(self): # noqa self.ip.dhcp_expose = True self.ip.save() - self.ip.address = '127.0.0.2' + self.ip.address = "127.0.0.2" with self.assertRaises( - ValidationError, - msg='Cannot change address when exposing in DHCP' + ValidationError, msg="Cannot change address when exposing in DHCP" ): self.ip.clean() @@ -573,110 +545,83 @@ def test_change_ethernet_with_dhcp_exposition_should_not_pass(self): # noqa self.ip.save() self.ip.ethernet = eth with self.assertRaises( - ValidationError, - msg='Cannot change ethernet when exposing in DHCP' + ValidationError, msg="Cannot change ethernet when exposing in DHCP" ): self.ip.clean() def test_duplicate_hostname_with_dhcp_exposition_should_not_pass(self): - name = 'random.hostname.net' + name = "random.hostname.net" network = NetworkFactory( - address='192.168.0.0/24', - network_environment=NetworkEnvironmentFactory() - ) - ip = IPAddressFactory( - hostname=name, address='192.168.0.1', - dhcp_expose=True + address="192.168.0.0/24", network_environment=NetworkEnvironmentFactory() ) + IPAddressFactory(hostname=name, address="192.168.0.1", dhcp_expose=True) self.ip.hostname = name - self.ip.address = '192.168.0.2' + self.ip.address = "192.168.0.2" self.ip.dhcp_expose = True with self.assertRaises( ValidationError, - msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'. - format( - hostname=name, - dc=network.network_environment.data_center - ) + msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( + hostname=name, dc=network.network_environment.data_center + ), ): self.ip.validate_hostname_uniqueness_in_dc(name) with self.assertRaises( ValidationError, - msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'. - format( - hostname=name, - dc=network.network_environment.data_center - ) + msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( + hostname=name, dc=network.network_environment.data_center + ), ): self.ip.clean() - def test_duplicate_hostname_in_different_networks_in_same_dc_should_not_pass(self): # noqa - name = 'random.hostname.net' + def test_duplicate_hostname_in_different_networks_in_same_dc_should_not_pass(self): # noqa + name = "random.hostname.net" network = NetworkFactory( - address='192.168.0.0/24', + address="192.168.0.0/24", network_environment=NetworkEnvironmentFactory( - data_center=DataCenterFactory( - name='DC1' - ) - ) + data_center=DataCenterFactory(name="DC1") + ), ) network1 = NetworkFactory( - address='1.1.0.0/24', + address="1.1.0.0/24", network_environment=NetworkEnvironmentFactory( - data_center=DataCenterFactory( - name='DC1' - ) - ) - ) - ip = IPAddressFactory( - hostname=name, address='192.168.0.1', - dhcp_expose=True + data_center=DataCenterFactory(name="DC1") + ), ) + IPAddressFactory(hostname=name, address="192.168.0.1", dhcp_expose=True) self.ip.hostname = name - self.ip.address = '1.1.0.2' + self.ip.address = "1.1.0.2" self.ip.dhcp_expose = True with self.assertRaises( ValidationError, - msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'. - format( - hostname=name, - dc=network.network_environment.data_center - ) + msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( + hostname=name, dc=network.network_environment.data_center + ), ): self.ip.validate_hostname_uniqueness_in_dc(name) with self.assertRaises( ValidationError, - msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'. - format( - hostname=name, - dc=network1.network_environment.data_center - ) + msg='Hostname "{hostname}" is already exposed in DHCP in {dc}.'.format( + hostname=name, dc=network1.network_environment.data_center + ), ): self.ip.clean() def test_duplicate_hostnames_in_different_dcs_should_pass(self): - name = 'random.hostname.net' - network1 = NetworkFactory( - address='1.1.0.0/24', + name = "random.hostname.net" + NetworkFactory( + address="1.1.0.0/24", network_environment=NetworkEnvironmentFactory( - data_center=DataCenterFactory( - name='DC1' - ) - ) + data_center=DataCenterFactory(name="DC1") + ), ) - network2 = NetworkFactory( - address='192.168.0.0/24', + NetworkFactory( + address="192.168.0.0/24", network_environment=NetworkEnvironmentFactory( - data_center=DataCenterFactory( - name='DC2' - ) - ) - ) - ip = IPAddressFactory( - hostname=name, address='1.1.0.1', - dhcp_expose=True + data_center=DataCenterFactory(name="DC2") + ), ) - self.ip.address = '192.168.0.1' + IPAddressFactory(hostname=name, address="1.1.0.1", dhcp_expose=True) + self.ip.address = "192.168.0.1" self.ip.hostname = name self.ip.dhcp_expose = True self.ip.validate_hostname_uniqueness_in_dc(name) @@ -684,52 +629,50 @@ def test_duplicate_hostnames_in_different_dcs_should_pass(self): class TestNetworkClassFilter(RalphTestCase): - def setUp(self): from ralph.networks.tests.factories import NetworkFactory + self.factory = RequestFactory() - self.request = self.factory.get('/') + self.request = self.factory.get("/") self.private_network = NetworkFactory( - name='private_network', - address='10.0.0.0/8' + name="private_network", address="10.0.0.0/8" ) self.public_network = NetworkFactory( - name='public_network', - address='5.0.0.0/21' + name="public_network", address="5.0.0.0/21" ) def test_finds_private_nets_when_param_private(self): filter_ = NetworkClassFilter( - field=Network._meta.get_field('address'), + field=Network._meta.get_field("address"), request=self.request, - params={'address': 'private'}, + params={"address": "private"}, model=Network, model_admin=NetworkAdmin, - field_path='address' + field_path="address", ) queryset = filter_.queryset(None, Network.objects.all()) self.assertEqual(queryset.count(), 1) def test_finds_public_nets_when_param_public(self): filter_ = NetworkClassFilter( - field=Network._meta.get_field('address'), + field=Network._meta.get_field("address"), request=self.request, - params={'address': 'public'}, + params={"address": "public"}, model=Network, model_admin=NetworkAdmin, - field_path='address' + field_path="address", ) queryset = filter_.queryset(None, Network.objects.all()) self.assertEqual(queryset.count(), 1) def test_finds_all_nets_when_no_param(self): filter_ = NetworkClassFilter( - field=Network._meta.get_field('address'), + field=Network._meta.get_field("address"), request=self.request, params={}, model=Network, model_admin=NetworkAdmin, - field_path='address' + field_path="address", ) queryset = filter_.queryset(None, Network.objects.all()) self.assertEqual(queryset.count(), 2) diff --git a/src/ralph/networks/tests/test_receivers.py b/src/ralph/networks/tests/test_receivers.py index 4c0c1b5519..3a08ac3775 100644 --- a/src/ralph/networks/tests/test_receivers.py +++ b/src/ralph/networks/tests/test_receivers.py @@ -10,46 +10,44 @@ class IPAddressReceiversTestCase(RalphTestCase): def setUp(self): - self.cloud_ip = IPAddressFactory( - ethernet__base_object=CloudHostFactory() - ) + self.cloud_ip = IPAddressFactory(ethernet__base_object=CloudHostFactory()) # fetch "clean" ip from db to fet base object instead of final instance # (cloud host in this case) self.cloud_ip = IPAddress.objects.get(address=self.cloud_ip.address) self.dc_asset_ip = IPAddressFactory( ethernet__base_object=DataCenterAssetFactory() ) - self.dc_asset_ip = IPAddress.objects.get( - address=self.dc_asset_ip.address - ) + self.dc_asset_ip = IPAddress.objects.get(address=self.dc_asset_ip.address) - @patch('ralph.networks.receivers.DNSaaS') + @patch("ralph.networks.receivers.DNSaaS") def test_should_not_send_event_to_dnsaas_when_nothing_is_changed(self, dnsaas_mock): update_dns_record(self.dc_asset_ip, False) dnsaas_mock.assert_not_called() dnsaas_mock().send_ipaddress_data.assert_not_called() - @patch('ralph.networks.receivers.DNSaaS') + @patch("ralph.networks.receivers.DNSaaS") def test_should_not_send_event_to_dnsaas_when_cloud_host(self, dnsaas_mock): - self.dc_asset_ip.hostname = 'myhost.mydc.net' + self.dc_asset_ip.hostname = "myhost.mydc.net" update_dns_record(self.cloud_ip, False) dnsaas_mock.assert_not_called() dnsaas_mock().send_ipaddress_data.assert_not_called() - @patch('ralph.networks.receivers.DNSaaS') + @patch("ralph.networks.receivers.DNSaaS") def test_should_send_event_to_dnsaas_when_asset(self, dnsaas_mock): old_hostname = self.dc_asset_ip.hostname - self.dc_asset_ip.hostname = 'myhost.mydc.net' + self.dc_asset_ip.hostname = "myhost.mydc.net" update_dns_record(self.dc_asset_ip, False) - dnsaas_mock().send_ipaddress_data.assert_called_with({ - 'action': 'update', - 'old': { - 'address': self.dc_asset_ip.address, - 'hostname': old_hostname, - }, - 'new': { - 'address': self.dc_asset_ip.address, - 'hostname': 'myhost.mydc.net', - }, - 'service_uid': self.dc_asset_ip.ethernet.base_object.service.uid - }) + dnsaas_mock().send_ipaddress_data.assert_called_with( + { + "action": "update", + "old": { + "address": self.dc_asset_ip.address, + "hostname": old_hostname, + }, + "new": { + "address": self.dc_asset_ip.address, + "hostname": "myhost.mydc.net", + }, + "service_uid": self.dc_asset_ip.ethernet.base_object.service.uid, + } + ) diff --git a/src/ralph/networks/views.py b/src/ralph/networks/views.py index c86cf359ea..0e915df4f5 100644 --- a/src/ralph/networks/views.py +++ b/src/ralph/networks/views.py @@ -14,16 +14,17 @@ class NetworkInline(RalphTabularInline): form = NetworkForm formset = NetworkInlineFormset model = Ethernet - exclude = ['model'] + exclude = ["model"] class NetworkTerminatorReadOnlyInline(RalphTabularM2MInline): model = Network extra = 0 show_change_link = True - verbose_name_plural = _('Terminators of') + verbose_name_plural = _("Terminators of") fields = [ - 'name', 'address', + "name", + "address", ] def get_readonly_fields(self, request, obj=None): @@ -34,39 +35,34 @@ def has_add_permission(self, request): class NetworkView(RalphDetailViewAdmin): - icon = 'chain' - name = 'network' - label = 'Network' - url_name = 'network' - admin_attribute_list_to_copy = ['available_networks'] - readonly_fields = ('available_networks',) + icon = "chain" + name = "network" + label = "Network" + url_name = "network" + admin_attribute_list_to_copy = ["available_networks"] + readonly_fields = ("available_networks",) inlines = [ NetworkInline, ] - fields = ('available_networks', ) + fields = ("available_networks",) @mark_safe def available_networks(self, instance): - networks = instance._get_available_networks( - as_query=True - ).select_related('network_environment') + networks = instance._get_available_networks(as_query=True).select_related( + "network_environment" + ) if networks: result = TableWithUrl( networks, - ['name', 'address', 'network_environment'], - url_field='name', + ["name", "address", "network_environment"], + url_field="name", ).render() else: - result = '–' + result = "–" return result - available_networks.short_description = _('Available networks') - fieldsets = ( - (_(''), { - 'fields': ( - 'available_networks', - ) - }), - ) + + available_networks.short_description = _("Available networks") + fieldsets = ((_(""), {"fields": ("available_networks",)}),) class NetworkWithTerminatorsView(NetworkView): diff --git a/src/ralph/notifications/__init__.py b/src/ralph/notifications/__init__.py index e11038db4b..301ae8f3e3 100644 --- a/src/ralph/notifications/__init__.py +++ b/src/ralph/notifications/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.notifications.apps.NotificationConfig' +default_app_config = "ralph.notifications.apps.NotificationConfig" diff --git a/src/ralph/notifications/apps.py b/src/ralph/notifications/apps.py index d5318a0990..e81bbfc3ec 100644 --- a/src/ralph/notifications/apps.py +++ b/src/ralph/notifications/apps.py @@ -7,17 +7,17 @@ class NotificationConfig(RalphAppConfig): - name = 'ralph.notifications' - verbose_name = 'Notifiaction' + name = "ralph.notifications" + verbose_name = "Notifiaction" def ready(self): if not settings.ENABLE_EMAIL_NOTIFICATION: return models = [ - 'data_center.DataCenterAsset', - 'data_center.Cluster', - 'virtual.VirtualServer', - 'virtual.CloudProject', + "data_center.DataCenterAsset", + "data_center.Cluster", + "virtual.VirtualServer", + "virtual.CloudProject", ] for model in models: post_commit(send_notification_for_model, model) diff --git a/src/ralph/notifications/sender.py b/src/ralph/notifications/sender.py index 5e80632013..2610d00eb4 100644 --- a/src/ralph/notifications/sender.py +++ b/src/ralph/notifications/sender.py @@ -12,54 +12,44 @@ logger = logging.getLogger(__name__) -@statsd.timer('notification') +@statsd.timer("notification") def send_notification_for_model(instance): - ServiceEnvironment = instance._meta.get_field('service_env').related_model - old_service_env_id = instance._previous_state['service_env_id'] + ServiceEnvironment = instance._meta.get_field("service_env").related_model + old_service_env_id = instance._previous_state["service_env_id"] new_service_env_id = instance.service_env_id if old_service_env_id and old_service_env_id != new_service_env_id: logger.info( - 'Sending mail notification for {}'.format(instance), + "Sending mail notification for {}".format(instance), extra={ - 'type': 'SEND_MAIL_NOTIFICATION_FOR_MODEL', - 'instance_id': instance.id, - 'content_type': instance.content_type.name, - 'notification_type': 'service_change', - } - ) - old_service_env = ServiceEnvironment.objects.get( - pk=old_service_env_id - ) - new_service_env = ServiceEnvironment.objects.get( - pk=new_service_env_id + "type": "SEND_MAIL_NOTIFICATION_FOR_MODEL", + "instance_id": instance.id, + "content_type": instance.content_type.name, + "notification_type": "service_change", + }, ) + old_service_env = ServiceEnvironment.objects.get(pk=old_service_env_id) + new_service_env = ServiceEnvironment.objects.get(pk=new_service_env_id) owners = [] - for field in ['business_owners', 'technical_owners']: + for field in ["business_owners", "technical_owners"]: owners.extend(list(getattr(old_service_env.service, field).all())) owners.extend(list(getattr(new_service_env.service, field).all())) emails = set([owner.email for owner in owners if owner.email]) if emails: context = { - 'old_service_env': old_service_env, - 'new_service_env': new_service_env, - 'object': instance, - 'user': get_current_user(), - 'settings': settings, - 'object_url': urljoin( + "old_service_env": old_service_env, + "new_service_env": new_service_env, + "object": instance, + "user": get_current_user(), + "settings": settings, + "object_url": urljoin( settings.RALPH_HOST_URL, instance.get_absolute_url() - ) + ), } - html_content = render_to_string( - 'notifications/html/message.html', - context - ) - text_content = render_to_string( - 'notifications/txt/message.txt', - context - ) - subject = 'Device has been assigned to Service: {} ({})'.format( + html_content = render_to_string("notifications/html/message.html", context) + text_content = render_to_string("notifications/txt/message.txt", context) + subject = "Device has been assigned to Service: {} ({})".format( new_service_env.service, instance ) msg = EmailMultiAlternatives( diff --git a/src/ralph/notifications/test_notification.py b/src/ralph/notifications/test_notification.py index 9f41a15191..70a631ace1 100644 --- a/src/ralph/notifications/test_notification.py +++ b/src/ralph/notifications/test_notification.py @@ -4,44 +4,33 @@ from django.test import TransactionTestCase from ralph.accounts.tests.factories import UserFactory -from ralph.assets.tests.factories import ( - ServiceEnvironmentFactory, - ServiceFactory -) +from ralph.assets.tests.factories import ServiceEnvironmentFactory, ServiceFactory from ralph.data_center.models import DataCenterAsset from ralph.data_center.tests.factories import DataCenterAssetFactory class NotificationTest(TransactionTestCase): - def test_if_notification_is_send_when_data_center_asset_is_saved(self): - old_service = ServiceFactory(name='test') - new_service = ServiceFactory(name='prod') - old_service.business_owners.add(UserFactory(email='test1@test.pl')) - new_service.business_owners.add(UserFactory(email='test2@test.pl')) + old_service = ServiceFactory(name="test") + new_service = ServiceFactory(name="prod") + old_service.business_owners.add(UserFactory(email="test1@test.pl")) + new_service.business_owners.add(UserFactory(email="test2@test.pl")) self.dca = DataCenterAssetFactory( - service_env=ServiceEnvironmentFactory( - service=old_service - ) + service_env=ServiceEnvironmentFactory(service=old_service) ) # fetch DCA to start with clean state in post_commit signals # (ex. invalidate call to notification handler during creating of DCA) self.dca = DataCenterAsset.objects.get(pk=self.dca.pk) - self.dca.service_env = ServiceEnvironmentFactory( - service=new_service - ) + self.dca.service_env = ServiceEnvironmentFactory(service=new_service) with transaction.atomic(): self.dca.save() self.assertEqual(len(mail.outbox), 1) self.assertEqual( - 'Device has been assigned to Service: {} ({})'.format( + "Device has been assigned to Service: {} ({})".format( new_service, self.dca ), - mail.outbox[0].subject - ) - self.assertCountEqual( - mail.outbox[0].to, - ['test1@test.pl', 'test2@test.pl'] + mail.outbox[0].subject, ) + self.assertCountEqual(mail.outbox[0].to, ["test1@test.pl", "test2@test.pl"]) diff --git a/src/ralph/operations/__init__.py b/src/ralph/operations/__init__.py index f313aff84d..beac33e557 100644 --- a/src/ralph/operations/__init__.py +++ b/src/ralph/operations/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.operations.apps.RalphOperationsConfig' +default_app_config = "ralph.operations.apps.RalphOperationsConfig" diff --git a/src/ralph/operations/admin.py b/src/ralph/operations/admin.py index ecd2553a21..f3628e8eba 100644 --- a/src/ralph/operations/admin.py +++ b/src/ralph/operations/admin.py @@ -21,17 +21,17 @@ Operation, OperationStatus, OperationType, - Problem + Problem, ) class OperationChangeList(RalphChangeList): - def get_filters(self, request): """Avoid using DISTINCT clause when base object filter is not used.""" - filter_specs, filter_specs_exist, lookup_params, use_distinct = \ - super(RalphChangeList, self).get_filters(request) + filter_specs, filter_specs_exist, lookup_params, use_distinct = super( + RalphChangeList, self + ).get_filters(request) filter_params = self.get_filters_params() @@ -39,15 +39,15 @@ def get_filters(self, request): filter_specs, filter_specs_exist, lookup_params, - use_distinct if filter_params.get('base_objects') else False + use_distinct if filter_params.get("base_objects") else False, ) @register(OperationType) class OperationTypeAdmin(RalphMPTTAdmin): - list_display = ('name', 'parent') - list_select_related = ('parent',) - search_fields = ['name'] + list_display = ("name", "parent") + list_select_related = ("parent",) + search_fields = ["name"] def has_delete_permission(self, request, obj=None): # disable delete @@ -56,8 +56,8 @@ def has_delete_permission(self, request, obj=None): @register(OperationStatus) class OperationStatusAdmin(RalphAdmin): - list_display = ('name',) - search_fields = ['name'] + list_display = ("name",) + search_fields = ["name"] class OperationAdminForm(RalphAdminForm): @@ -66,7 +66,7 @@ def __init__(self, *args, **kwargs): _operation_type_subtree = self.instance._operation_type_subtree if _operation_type_subtree: root = OperationType.objects.get(pk=_operation_type_subtree) - self.fields['type'].queryset = self.fields['type'].queryset.filter( + self.fields["type"].queryset = self.fields["type"].queryset.filter( pk__in=root.get_descendants(include_self=True) ) @@ -74,42 +74,42 @@ def __init__(self, *args, **kwargs): class ServiceEnvironmentAndConfigurationPathMixin(object): def get_list_display(self, request): list_display = super().get_list_display(request) - return list_display + ['get_services', 'get_configuration_path'] + return list_display + ["get_services", "get_configuration_path"] def _get_related_objects(self, obj, field): if not obj.base_objects: - return '-' - objects = Counter([ - str(getattr(base_object, field)) - for base_object in obj.base_objects.all() - ]) - return '
    '.join([ - '{}: {}'.format(name, count) - for name, count in objects.most_common() - ]) + return "-" + objects = Counter( + [str(getattr(base_object, field)) for base_object in obj.base_objects.all()] + ) + return "
    ".join( + ["{}: {}".format(name, count) for name, count in objects.most_common()] + ) @mark_safe def get_services(self, obj): - return self._get_related_objects(obj, 'service_env') - get_services.short_description = _('services') + return self._get_related_objects(obj, "service_env") + + get_services.short_description = _("services") @mark_safe def get_configuration_path(self, obj): - return self._get_related_objects(obj=obj, field='configuration_path') - get_configuration_path.short_description = _('configuration path') + return self._get_related_objects(obj=obj, field="configuration_path") + + get_configuration_path.short_description = _("configuration path") def get_queryset(self, request): qs = super().get_queryset(request) qs = qs.prefetch_related( Prefetch( - 'base_objects', + "base_objects", queryset=BaseObject.objects.distinct().select_related( - 'configuration_path', - 'configuration_path__module', - 'service_env', - 'service_env__service', - 'service_env__environment', - ) + "configuration_path", + "configuration_path__module", + "service_env", + "service_env__service", + "service_env__environment", + ), ) ) return qs @@ -117,46 +117,63 @@ def get_queryset(self, request): @register(Operation) class OperationAdmin( - AttachmentsMixin, - ServiceEnvironmentAndConfigurationPathMixin, - RalphAdmin + AttachmentsMixin, ServiceEnvironmentAndConfigurationPathMixin, RalphAdmin ): - search_fields = ['title', 'description', 'ticket_id'] + search_fields = ["title", "description", "ticket_id"] list_filter = [ - 'type', ('status', StatusFilter), 'reporter', 'assignee', - 'created_date', 'update_date', 'resolved_date', 'base_objects', - 'base_objects__service_env', 'base_objects__configuration_path' + "type", + ("status", StatusFilter), + "reporter", + "assignee", + "created_date", + "update_date", + "resolved_date", + "base_objects", + "base_objects__service_env", + "base_objects__configuration_path", ] - list_display = ['title', 'type', 'created_date', 'status', 'reporter', - 'get_ticket_url'] - list_select_related = ('reporter', 'type', 'status') - raw_id_fields = ['assignee', 'reporter', 'base_objects'] + list_display = [ + "title", + "type", + "created_date", + "status", + "reporter", + "get_ticket_url", + ] + list_select_related = ("reporter", "type", "status") + raw_id_fields = ["assignee", "reporter", "base_objects"] resource_class = resources.OperationResource form = OperationAdminForm fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'type', 'title', 'status', 'reporter', 'assignee', - 'description', 'ticket_id', 'created_date', 'update_date', - 'resolved_date', - ) - }), - (_('Objects'), { - 'fields': ( - 'base_objects', - ) - }), + ( + _("Basic info"), + { + "fields": ( + "type", + "title", + "status", + "reporter", + "assignee", + "description", + "ticket_id", + "created_date", + "update_date", + "resolved_date", + ) + }, + ), + (_("Objects"), {"fields": ("base_objects",)}), ) @mark_safe def get_ticket_url(self, obj): return '{ticket_id}'.format( - ticket_url=obj.ticket_url, - ticket_id=obj.ticket_id + ticket_url=obj.ticket_url, ticket_id=obj.ticket_id ) - get_ticket_url.short_description = _('ticket ID') - get_ticket_url.admin_order_field = 'ticket_id' + + get_ticket_url.short_description = _("ticket ID") + get_ticket_url.admin_order_field = "ticket_id" def get_changelist(self, request, **kwargs): return OperationChangeList @@ -180,20 +197,16 @@ class ProblemAdmin(OperationAdmin): @register(Failure) class FailureAdmin(OperationAdmin): list_filter = OperationAdmin.list_filter + [ - 'base_objects__asset__model__manufacturer' + "base_objects__asset__model__manufacturer" ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Allow to edit datetime fields for case when new entries are # created manually. - self.formfield_overrides[DateTimeField] = { - 'widget': AdminDateTimeWidget - } + self.formfield_overrides[DateTimeField] = {"widget": AdminDateTimeWidget} def get_changeform_initial_data(self, request): initial_data = super().get_changeform_initial_data(request) - initial_data['created_date'] = timezone.now().strftime( - '%Y-%m-%d %H:%M:%S' - ) + initial_data["created_date"] = timezone.now().strftime("%Y-%m-%d %H:%M:%S") return initial_data diff --git a/src/ralph/operations/api.py b/src/ralph/operations/api.py index a950ad5074..0824f09839 100644 --- a/src/ralph/operations/api.py +++ b/src/ralph/operations/api.py @@ -9,7 +9,6 @@ class OperationTypeSerializer(RalphAPISerializer): - class Meta: model = OperationType depth = 1 @@ -17,7 +16,6 @@ class Meta: class OperationStatusSerializer(RalphAPISerializer): - class Meta: model = OperationStatus depth = 1 @@ -28,26 +26,26 @@ class OperationSerializer(RalphAPISerializer): type = SlugRelatedField( many=False, read_only=False, - slug_field='name', - queryset=OperationType.objects.all() + slug_field="name", + queryset=OperationType.objects.all(), ) assignee = SlugRelatedField( many=False, read_only=False, - slug_field='username', - queryset=RalphUser.objects.all() + slug_field="username", + queryset=RalphUser.objects.all(), ) reporter = SlugRelatedField( many=False, read_only=False, - slug_field='username', - queryset=RalphUser.objects.all() + slug_field="username", + queryset=RalphUser.objects.all(), ) status = SlugRelatedField( many=False, read_only=False, - slug_field='name', - queryset=OperationStatus.objects.all() + slug_field="name", + queryset=OperationStatus.objects.all(), ) class Meta: @@ -60,18 +58,26 @@ class OperationViewSet(RalphAPIViewSet): renderer_classes = renderer_classes_without_form(RalphAPIViewSet.renderer_classes) queryset = Operation.objects.all().prefetch_related( Prefetch( - lookup='base_objects', - queryset=BaseObject.objects.select_related('parent') + lookup="base_objects", queryset=BaseObject.objects.select_related("parent") ) ) serializer_class = OperationSerializer save_serializer_class = OperationSerializer - select_related = ['type', 'assignee', 'reporter', 'status'] + select_related = ["type", "assignee", "reporter", "status"] prefetch_related = ["tags", "base_objects__tags"] filter_fields = [ - 'id', 'title', 'description', 'status', 'status', 'ticket_id', - 'created_date', 'update_date', 'resolved_date', 'type', - 'assignee', 'reporter' + "id", + "title", + "description", + "status", + "status", + "ticket_id", + "created_date", + "update_date", + "resolved_date", + "type", + "assignee", + "reporter", ] @@ -85,7 +91,7 @@ class OperationStatusViewSet(RalphAPIViewSet): serializer_class = OperationStatusSerializer -router.register(r'operation', OperationViewSet) -router.register(r'operationtype', OperationTypeViewSet) -router.register(r'operationstatus', OperationStatusViewSet) +router.register(r"operation", OperationViewSet) +router.register(r"operationtype", OperationTypeViewSet) +router.register(r"operationstatus", OperationStatusViewSet) urlpatterns = [] diff --git a/src/ralph/operations/apps.py b/src/ralph/operations/apps.py index 41e19fcdf8..691bb2d2e2 100644 --- a/src/ralph/operations/apps.py +++ b/src/ralph/operations/apps.py @@ -2,10 +2,11 @@ class RalphOperationsConfig(RalphAppConfig): - name = 'ralph.operations' - label = 'operations' - verbose_name = 'Ralph Operations' + name = "ralph.operations" + label = "operations" + verbose_name = "Ralph Operations" def ready(self): from ralph.operations.changemanagement.subscribtions import receive_chm_event # noqa + super().ready() diff --git a/src/ralph/operations/changemanagement/exceptions.py b/src/ralph/operations/changemanagement/exceptions.py index 5a475e7ab3..c559ad4a3c 100644 --- a/src/ralph/operations/changemanagement/exceptions.py +++ b/src/ralph/operations/changemanagement/exceptions.py @@ -1,2 +1,2 @@ class IgnoreOperation(Exception): - message = 'Ignoring the opertaion.' + message = "Ignoring the opertaion." diff --git a/src/ralph/operations/changemanagement/jira.py b/src/ralph/operations/changemanagement/jira.py index 0b1000f08e..48fa452c7c 100644 --- a/src/ralph/operations/changemanagement/jira.py +++ b/src/ralph/operations/changemanagement/jira.py @@ -8,28 +8,28 @@ def get_title(event_data): - return event_data['issue']['fields']['summary'] + return event_data["issue"]["fields"]["summary"] def get_description(event_data): - return event_data['issue']['fields']['description'] + return event_data["issue"]["fields"]["description"] def get_ticket_id(event_data): - return event_data['issue']['key'] + return event_data["issue"]["key"] def get_operation_status(event_data): - return event_data['issue']['fields']['status']['name'] + return event_data["issue"]["fields"]["status"]["name"] def get_operation_name(event_data): - return event_data['issue']['fields']['issuetype']['name'] + return event_data["issue"]["fields"]["issuetype"]["name"] def get_assignee_username(event_data): try: - return event_data['issue']['fields']['assignee']['key'] + return event_data["issue"]["fields"]["assignee"]["key"] except TypeError: # NOTE(romcheg): This means there is no assignee. return None @@ -37,31 +37,31 @@ def get_assignee_username(event_data): def get_reporter_username(event_data): try: - return event_data['issue']['fields']['reporter']['key'] + return event_data["issue"]["fields"]["reporter"]["key"] except TypeError: # NOTE(romcheg): This means the reporter is not specified. return None def get_creation_date(event_data): - return _safe_load_datetime(event_data, 'created') + return _safe_load_datetime(event_data, "created") def get_last_update_date(event_data): - return _safe_load_datetime(event_data, 'updated') + return _safe_load_datetime(event_data, "updated") def get_resolution_date(event_data): - return _safe_load_datetime(event_data, 'resolutiondate') + return _safe_load_datetime(event_data, "resolutiondate") def _safe_load_datetime(event_data, field): """Safely serialize an ISO 8601 datetime string into a datetime object.""" try: - datetime_str = event_data['issue']['fields'][field] - return parse_datetime( - datetime_str - ).astimezone(timezone.utc).replace(tzinfo=None) + datetime_str = event_data["issue"]["fields"][field] + return ( + parse_datetime(datetime_str).astimezone(timezone.utc).replace(tzinfo=None) + ) except: return None diff --git a/src/ralph/operations/changemanagement/subscribtions.py b/src/ralph/operations/changemanagement/subscribtions.py index c128e78c68..4640d86473 100644 --- a/src/ralph/operations/changemanagement/subscribtions.py +++ b/src/ralph/operations/changemanagement/subscribtions.py @@ -30,8 +30,7 @@ def _safe_load_user(username): model = get_user_model() user, _ = model.objects.get_or_create( - username=username, - defaults={'is_active': False} + username=username, defaults={"is_active": False} ) return user @@ -51,9 +50,7 @@ def _safe_load_status(status_name): status, created = OperationStatus.objects.get_or_create(name=status_name) if created: - logger.warning( - 'Received an operation with a new status %s.', status_name - ) + logger.warning("Received an operation with a new status %s.", status_name) return status @@ -65,18 +62,25 @@ def _load_base_objects(object_ids): @transaction.atomic -def record_operation(title, status_name, description, operation_name, ticket_id, - assignee_username=None, reporter_username=None, - created_date=None, update_date=None, resolution_date=None, - base_object_ids=None): - +def record_operation( + title, + status_name, + description, + operation_name, + ticket_id, + assignee_username=None, + reporter_username=None, + created_date=None, + update_date=None, + resolution_date=None, + base_object_ids=None, +): operation_type = _safe_load_operation_type(operation_name) # NOTE(romcheg): Changes of an unknown type should not be recorded. if operation_type is None: logger.warning( - 'Not recording operation with the ' - 'unknown type: %s.', operation_name + "Not recording operation with the " "unknown type: %s.", operation_name ) return @@ -91,8 +95,8 @@ def record_operation(title, status_name, description, operation_name, ticket_id, reporter=_safe_load_user(reporter_username), created_date=created_date, update_date=update_date, - resolved_date=resolution_date - ) + resolved_date=resolution_date, + ), ) if base_object_ids: @@ -100,7 +104,7 @@ def record_operation(title, status_name, description, operation_name, ticket_id, operation.save() -@pyhermes.subscriber(topic=settings.HERMES_CHANGE_MGMT_TOPICS['CHANGES']) +@pyhermes.subscriber(topic=settings.HERMES_CHANGE_MGMT_TOPICS["CHANGES"]) def receive_chm_event(event_data): """Process messages from the change management system.""" try: @@ -110,25 +114,22 @@ def receive_chm_event(event_data): ticket_id=change_processor.get_ticket_id(event_data), status_name=change_processor.get_operation_status(event_data), operation_name=change_processor.get_operation_name(event_data), - assignee_username=change_processor.get_assignee_username( - event_data - ), - reporter_username=change_processor.get_reporter_username( - event_data - ), + assignee_username=change_processor.get_assignee_username(event_data), + reporter_username=change_processor.get_reporter_username(event_data), created_date=change_processor.get_creation_date(event_data), update_date=change_processor.get_last_update_date(event_data), resolution_date=change_processor.get_resolution_date(event_data), base_object_ids=( base_object_loader.get_baseobjects_ids(event_data) - if base_object_loader is not None else None - ) + if base_object_loader is not None + else None + ), ) except IgnoreOperation as e: logger.warning(e.message) except Exception as e: logger.exception( - 'Encountered an unexpected failure while handling a change ' - 'management event.', - exc_info=e + "Encountered an unexpected failure while handling a change " + "management event.", + exc_info=e, ) diff --git a/src/ralph/operations/filters.py b/src/ralph/operations/filters.py index 4f3d7a13e8..a0866ee1d1 100644 --- a/src/ralph/operations/filters.py +++ b/src/ralph/operations/filters.py @@ -3,20 +3,15 @@ class StatusFilter(ChoicesListFilter): - def __init__(self, *args, **kwargs): super(StatusFilter, self).__init__(*args, **kwargs) - statuses = OperationStatus.objects.order_by('name') + statuses = OperationStatus.objects.order_by("name") - self._choices_list = [ - (status.id, status.name) for status in statuses - ] + self._choices_list = [(status.id, status.name) for status in statuses] def queryset(self, request, queryset): if not self.value(): return queryset - return queryset.filter( - status_id=int(self.value()) - ) + return queryset.filter(status_id=int(self.value())) diff --git a/src/ralph/operations/migrations/0001_initial.py b/src/ralph/operations/migrations/0001_initial.py index ffbc7652ce..cbee8e4376 100644 --- a/src/ralph/operations/migrations/0001_initial.py +++ b/src/ralph/operations/migrations/0001_initial.py @@ -11,88 +11,180 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0004_auto_20151204_0758'), + ("assets", "0004_auto_20151204_0758"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('taggit', '0002_auto_20150616_2121'), + ("taggit", "0002_auto_20150616_2121"), ] operations = [ migrations.CreateModel( - name='Operation', + name="Operation", fields=[ - ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), - ('title', models.CharField(max_length=350, verbose_name='title')), - ('description', models.TextField(blank=True, verbose_name='description', null=True)), - ('status', models.PositiveIntegerField(verbose_name='status', choices=[(1, 'open'), (2, 'in progress'), (3, 'resolved'), (4, 'closed')])), - ('ticket_id', ralph.lib.mixins.fields.NullableCharField(help_text='External system ticket identifier', blank=True, max_length=20, verbose_name='ticket id', null=True)), - ('created_date', models.DateTimeField(blank=True, verbose_name='created date', null=True)), - ('update_date', models.DateTimeField(blank=True, verbose_name='updated date', null=True)), - ('resolved_date', models.DateTimeField(blank=True, verbose_name='resolved date', null=True)), - ('asignee', models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='asignee', null=True, related_name='operations', blank=True, on_delete=models.PROTECT)), - ('base_objects', models.ManyToManyField(blank=True, to='assets.BaseObject', verbose_name='objects', related_name='operations')), - ('tags', taggit.managers.TaggableManager(to='taggit.Tag', help_text='A comma-separated list of tags.', verbose_name='Tags', through='taggit.TaggedItem', blank=True)), + ( + "id", + models.AutoField( + primary_key=True, + verbose_name="ID", + auto_created=True, + serialize=False, + ), + ), + ("title", models.CharField(max_length=350, verbose_name="title")), + ( + "description", + models.TextField(blank=True, verbose_name="description", null=True), + ), + ( + "status", + models.PositiveIntegerField( + verbose_name="status", + choices=[ + (1, "open"), + (2, "in progress"), + (3, "resolved"), + (4, "closed"), + ], + ), + ), + ( + "ticket_id", + ralph.lib.mixins.fields.NullableCharField( + help_text="External system ticket identifier", + blank=True, + max_length=20, + verbose_name="ticket id", + null=True, + ), + ), + ( + "created_date", + models.DateTimeField( + blank=True, verbose_name="created date", null=True + ), + ), + ( + "update_date", + models.DateTimeField( + blank=True, verbose_name="updated date", null=True + ), + ), + ( + "resolved_date", + models.DateTimeField( + blank=True, verbose_name="resolved date", null=True + ), + ), + ( + "asignee", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, + verbose_name="asignee", + null=True, + related_name="operations", + blank=True, + on_delete=models.PROTECT, + ), + ), + ( + "base_objects", + models.ManyToManyField( + blank=True, + to="assets.BaseObject", + verbose_name="objects", + related_name="operations", + ), + ), + ( + "tags", + taggit.managers.TaggableManager( + to="taggit.Tag", + help_text="A comma-separated list of tags.", + verbose_name="Tags", + through="taggit.TaggedItem", + blank=True, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='OperationType', + name="OperationType", fields=[ - ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), - ('name', models.CharField(max_length=255, verbose_name='name', unique=True)), - ('lft', models.PositiveIntegerField(editable=False, db_index=True)), - ('rght', models.PositiveIntegerField(editable=False, db_index=True)), - ('tree_id', models.PositiveIntegerField(editable=False, db_index=True)), - ('level', models.PositiveIntegerField(editable=False, db_index=True)), - ('parent', mptt.fields.TreeForeignKey(to='operations.OperationType', null=True, related_name='children', blank=True, on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + primary_key=True, + verbose_name="ID", + auto_created=True, + serialize=False, + ), + ), + ( + "name", + models.CharField(max_length=255, verbose_name="name", unique=True), + ), + ("lft", models.PositiveIntegerField(editable=False, db_index=True)), + ("rght", models.PositiveIntegerField(editable=False, db_index=True)), + ("tree_id", models.PositiveIntegerField(editable=False, db_index=True)), + ("level", models.PositiveIntegerField(editable=False, db_index=True)), + ( + "parent", + mptt.fields.TreeForeignKey( + to="operations.OperationType", + null=True, + related_name="children", + blank=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.AddField( - model_name='operation', - name='type', - field=mptt.fields.TreeForeignKey(to='operations.OperationType', verbose_name='type', on_delete=django.db.models.deletion.CASCADE), + model_name="operation", + name="type", + field=mptt.fields.TreeForeignKey( + to="operations.OperationType", + verbose_name="type", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.CreateModel( - name='Change', - fields=[ - ], + name="Change", + fields=[], options={ - 'proxy': True, + "proxy": True, }, - bases=('operations.operation',), + bases=("operations.operation",), ), migrations.CreateModel( - name='Failure', - fields=[ - ], + name="Failure", + fields=[], options={ - 'proxy': True, + "proxy": True, }, - bases=('operations.operation',), + bases=("operations.operation",), ), migrations.CreateModel( - name='Incident', - fields=[ - ], + name="Incident", + fields=[], options={ - 'proxy': True, + "proxy": True, }, - bases=('operations.operation',), + bases=("operations.operation",), ), migrations.CreateModel( - name='Problem', - fields=[ - ], + name="Problem", + fields=[], options={ - 'proxy': True, + "proxy": True, }, - bases=('operations.operation',), + bases=("operations.operation",), ), ] diff --git a/src/ralph/operations/migrations/0002_auto_20151218_1029.py b/src/ralph/operations/migrations/0002_auto_20151218_1029.py index c1b7208de4..aaca53ee1b 100644 --- a/src/ralph/operations/migrations/0002_auto_20151218_1029.py +++ b/src/ralph/operations/migrations/0002_auto_20151218_1029.py @@ -4,27 +4,39 @@ from django.db import migrations OPERATION_TYPES = ( - (1, 'Change', []), - (101, 'Incident', []), - (201, 'Problem', []), - (301, 'Failure', [ - (302, 'Hardware Failure', [ - (303, 'Disk', []), - (304, 'Controller', []), - (305, 'RAM', []), - (306, 'Eth card', [ - (307, 'Eth card 1Gb', []), - (308, 'Eth card 10Gb', []), - ]), - (309, 'Management Module', []), - (310, 'Power supply', []), - (311, 'Fan', []), - (312, 'SFP', []), - (313, 'Motherboard', []), - (314, 'Firmware upgrade', []), - (315, 'Backplane', []), - ]) - ]), + (1, "Change", []), + (101, "Incident", []), + (201, "Problem", []), + ( + 301, + "Failure", + [ + ( + 302, + "Hardware Failure", + [ + (303, "Disk", []), + (304, "Controller", []), + (305, "RAM", []), + ( + 306, + "Eth card", + [ + (307, "Eth card 1Gb", []), + (308, "Eth card 10Gb", []), + ], + ), + (309, "Management Module", []), + (310, "Power supply", []), + (311, "Fan", []), + (312, "SFP", []), + (313, "Motherboard", []), + (314, "Firmware upgrade", []), + (315, "Backplane", []), + ], + ) + ], + ), ) @@ -34,7 +46,7 @@ def load_operation(model, obj_id, name, parent, children): pk=obj_id, name=name, parent=parent, - **{'lft': 0, 'rght': 0, 'level': 0, 'tree_id': 0} + **{"lft": 0, "rght": 0, "level": 0, "tree_id": 0}, ) for child_id, child_name, child_children in children: load_operation(model, child_id, child_name, obj, child_children) @@ -52,13 +64,10 @@ def unload_initial_data(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('operations', '0001_initial'), + ("operations", "0001_initial"), ] operations = [ - migrations.RunPython( - load_initial_data, reverse_code=unload_initial_data - ), + migrations.RunPython(load_initial_data, reverse_code=unload_initial_data), ] diff --git a/src/ralph/operations/migrations/0003_auto_20160303_1114.py b/src/ralph/operations/migrations/0003_auto_20160303_1114.py index efc69d0729..271cafe321 100644 --- a/src/ralph/operations/migrations/0003_auto_20160303_1114.py +++ b/src/ralph/operations/migrations/0003_auto_20160303_1114.py @@ -6,20 +6,34 @@ class Migration(migrations.Migration): - dependencies = [ - ('operations', '0002_auto_20151218_1029'), + ("operations", "0002_auto_20151218_1029"), ] operations = [ migrations.AlterField( - model_name='operation', - name='status', - field=models.PositiveIntegerField(verbose_name='status', default=1, choices=[(1, 'open'), (2, 'in progress'), (3, 'resolved'), (4, 'closed')]), + model_name="operation", + name="status", + field=models.PositiveIntegerField( + verbose_name="status", + default=1, + choices=[ + (1, "open"), + (2, "in progress"), + (3, "resolved"), + (4, "closed"), + ], + ), ), migrations.AlterField( - model_name='operation', - name='ticket_id', - field=ralph.lib.mixins.fields.TicketIdField(blank=True, max_length=200, verbose_name='ticket ID', null=True, help_text='External system ticket identifier'), + model_name="operation", + name="ticket_id", + field=ralph.lib.mixins.fields.TicketIdField( + blank=True, + max_length=200, + verbose_name="ticket ID", + null=True, + help_text="External system ticket identifier", + ), ), ] diff --git a/src/ralph/operations/migrations/0004_auto_20160307_1138.py b/src/ralph/operations/migrations/0004_auto_20160307_1138.py index ec4fef0e64..7d9579a1cc 100644 --- a/src/ralph/operations/migrations/0004_auto_20160307_1138.py +++ b/src/ralph/operations/migrations/0004_auto_20160307_1138.py @@ -1,20 +1,25 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.models class Migration(migrations.Migration): - dependencies = [ - ('operations', '0003_auto_20160303_1114'), + ("operations", "0003_auto_20160303_1114"), ] operations = [ migrations.AlterField( - model_name='operation', - name='tags', - field=ralph.lib.mixins.models.TaggableManager(blank=True, verbose_name='Tags', help_text='A comma-separated list of tags.', to='taggit.Tag', through='taggit.TaggedItem'), + model_name="operation", + name="tags", + field=ralph.lib.mixins.models.TaggableManager( + blank=True, + verbose_name="Tags", + help_text="A comma-separated list of tags.", + to="taggit.Tag", + through="taggit.TaggedItem", + ), ), ] diff --git a/src/ralph/operations/migrations/0005_auto_20170323_1425.py b/src/ralph/operations/migrations/0005_auto_20170323_1425.py index 09f8128c01..c0d3f385ff 100644 --- a/src/ralph/operations/migrations/0005_auto_20170323_1425.py +++ b/src/ralph/operations/migrations/0005_auto_20170323_1425.py @@ -1,20 +1,26 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('operations', '0004_auto_20160307_1138'), + ("operations", "0004_auto_20160307_1138"), ] operations = [ migrations.AlterField( - model_name='operation', - name='ticket_id', - field=ralph.lib.mixins.fields.TicketIdField(null=True, unique=False, max_length=200, verbose_name='ticket id', blank=True, help_text='External system ticket identifier'), + model_name="operation", + name="ticket_id", + field=ralph.lib.mixins.fields.TicketIdField( + null=True, + unique=False, + max_length=200, + verbose_name="ticket id", + blank=True, + help_text="External system ticket identifier", + ), ), ] diff --git a/src/ralph/operations/migrations/0006_auto_20170323_1530.py b/src/ralph/operations/migrations/0006_auto_20170323_1530.py index 541d4ebff5..edc18c3a18 100644 --- a/src/ralph/operations/migrations/0006_auto_20170323_1530.py +++ b/src/ralph/operations/migrations/0006_auto_20170323_1530.py @@ -5,15 +5,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('operations', '0005_auto_20170323_1425'), + ("operations", "0005_auto_20170323_1425"), ] operations = [ migrations.AlterField( - model_name='operation', - name='status', - field=models.PositiveIntegerField(verbose_name='status', choices=[(1, 'open'), (2, 'in progress'), (3, 'resolved'), (4, 'closed'), (5, 'reopened'), (6, 'todo'), (7, 'blocked')], default=1), + model_name="operation", + name="status", + field=models.PositiveIntegerField( + verbose_name="status", + choices=[ + (1, "open"), + (2, "in progress"), + (3, "resolved"), + (4, "closed"), + (5, "reopened"), + (6, "todo"), + (7, "blocked"), + ], + default=1, + ), ), ] diff --git a/src/ralph/operations/migrations/0007_auto_20170328_1728.py b/src/ralph/operations/migrations/0007_auto_20170328_1728.py index 10ea16b4c4..e37159fce2 100644 --- a/src/ralph/operations/migrations/0007_auto_20170328_1728.py +++ b/src/ralph/operations/migrations/0007_auto_20170328_1728.py @@ -6,16 +6,13 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('operations', '0006_auto_20170323_1530'), + ("operations", "0006_auto_20170323_1530"), ] operations = [ migrations.RenameField( - model_name='operation', - old_name='asignee', - new_name='assignee' + model_name="operation", old_name="asignee", new_name="assignee" ) ] diff --git a/src/ralph/operations/migrations/0008_auto_20170331_0952.py b/src/ralph/operations/migrations/0008_auto_20170331_0952.py index 3b3f7c6f78..599fe874f9 100644 --- a/src/ralph/operations/migrations/0008_auto_20170331_0952.py +++ b/src/ralph/operations/migrations/0008_auto_20170331_0952.py @@ -7,15 +7,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('operations', '0007_auto_20170328_1728'), + ("operations", "0007_auto_20170328_1728"), ] operations = [ migrations.AlterField( - model_name='operation', - name='assignee', - field=models.ForeignKey(verbose_name='assignee', blank=True, to=settings.AUTH_USER_MODEL, null=True, related_name='operations', on_delete=django.db.models.deletion.PROTECT), + model_name="operation", + name="assignee", + field=models.ForeignKey( + verbose_name="assignee", + blank=True, + to=settings.AUTH_USER_MODEL, + null=True, + related_name="operations", + on_delete=django.db.models.deletion.PROTECT, + ), ), ] diff --git a/src/ralph/operations/migrations/0009_auto_20170403_1112.py b/src/ralph/operations/migrations/0009_auto_20170403_1112.py index 4495f05c7a..004766bdef 100644 --- a/src/ralph/operations/migrations/0009_auto_20170403_1112.py +++ b/src/ralph/operations/migrations/0009_auto_20170403_1112.py @@ -1,20 +1,26 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.fields class Migration(migrations.Migration): - dependencies = [ - ('operations', '0008_auto_20170331_0952'), + ("operations", "0008_auto_20170331_0952"), ] operations = [ migrations.AlterField( - model_name='operation', - name='ticket_id', - field=ralph.lib.mixins.fields.TicketIdField(null=True, max_length=200, verbose_name='ticket id', unique=True, blank=True, help_text='External system ticket identifier'), + model_name="operation", + name="ticket_id", + field=ralph.lib.mixins.fields.TicketIdField( + null=True, + max_length=200, + verbose_name="ticket id", + unique=True, + blank=True, + help_text="External system ticket identifier", + ), ), ] diff --git a/src/ralph/operations/migrations/0010_auto_20170410_1031.py b/src/ralph/operations/migrations/0010_auto_20170410_1031.py index 65a329ff42..6aec4ae28c 100644 --- a/src/ralph/operations/migrations/0010_auto_20170410_1031.py +++ b/src/ralph/operations/migrations/0010_auto_20170410_1031.py @@ -12,13 +12,13 @@ class OldOperationStatus(Choices): _ = Choices.Choice - opened = _('open') - in_progress = _('in progress') - resolved = _('resolved') - closed = _('closed') - reopened = _('reopened') - todo = _('todo') - blocked = _('blocked') + opened = _("open") + in_progress = _("in progress") + resolved = _("resolved") + closed = _("closed") + reopened = _("reopened") + todo = _("todo") + blocked = _("blocked") def safe_convert_status(status_name): @@ -26,13 +26,13 @@ def safe_convert_status(status_name): status_conf = settings.CHANGE_MGMT_OPERATION_STATUSES status_map = { - OldOperationStatus.opened.raw: status_conf['OPENED'], - OldOperationStatus.in_progress.raw: status_conf['IN_PROGRESS'], - OldOperationStatus.resolved.raw: status_conf['RESOLVED'], - OldOperationStatus.closed.raw: status_conf['CLOSED'], - OldOperationStatus.reopened.raw: status_conf['REOPENED'], - OldOperationStatus.todo.raw: status_conf['TODO'], - OldOperationStatus.blocked.raw: status_conf['BLOCKED'] + OldOperationStatus.opened.raw: status_conf["OPENED"], + OldOperationStatus.in_progress.raw: status_conf["IN_PROGRESS"], + OldOperationStatus.resolved.raw: status_conf["RESOLVED"], + OldOperationStatus.closed.raw: status_conf["CLOSED"], + OldOperationStatus.reopened.raw: status_conf["REOPENED"], + OldOperationStatus.todo.raw: status_conf["TODO"], + OldOperationStatus.blocked.raw: status_conf["BLOCKED"], } return status_map[status_name] @@ -41,49 +41,43 @@ def safe_convert_status(status_name): def load_old_operation_status(foo, bar): - for st_id, st_name in OldOperationStatus(): - OperationStatus.objects.create( - id=st_id, - name=safe_convert_status(st_name) - ) + OperationStatus.objects.create(id=st_id, name=safe_convert_status(st_name)) class Migration(migrations.Migration): - dependencies = [ - ('operations', '0009_auto_20170403_1112'), + ("operations", "0009_auto_20170403_1112"), ] operations = [ migrations.CreateModel( - name='OperationStatus', + name="OperationStatus", fields=[ ( - 'id', + "id", models.AutoField( - serialize=False, primary_key=True, - auto_created=True, verbose_name='ID' - ) + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), ), ( - 'name', - models.CharField( - verbose_name='name', - max_length=255, - unique=True - ) + "name", + models.CharField(verbose_name="name", max_length=255, unique=True), ), ], - options={'ordering': ['name']} + options={"ordering": ["name"]}, ), migrations.RunPython(load_old_operation_status, atomic=True), migrations.AlterField( - model_name='operation', - name='status', + model_name="operation", + name="status", field=models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, - to='operations.OperationStatus', verbose_name='status' + to="operations.OperationStatus", + verbose_name="status", ), ), ] diff --git a/src/ralph/operations/migrations/0011_operation_reporter.py b/src/ralph/operations/migrations/0011_operation_reporter.py index eed0229a6d..f3249f1e46 100644 --- a/src/ralph/operations/migrations/0011_operation_reporter.py +++ b/src/ralph/operations/migrations/0011_operation_reporter.py @@ -7,16 +7,22 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('operations', '0010_auto_20170410_1031'), + ("operations", "0010_auto_20170410_1031"), ] operations = [ migrations.AddField( - model_name='operation', - name='reporter', - field=models.ForeignKey(null=True, blank=True, verbose_name='reporter', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.PROTECT, related_name='reported_operations'), + model_name="operation", + name="reporter", + field=models.ForeignKey( + null=True, + blank=True, + verbose_name="reporter", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.PROTECT, + related_name="reported_operations", + ), ), ] diff --git a/src/ralph/operations/migrations/0012_auto_20211206_1347.py b/src/ralph/operations/migrations/0012_auto_20211206_1347.py index e552d0e230..a77b04570a 100644 --- a/src/ralph/operations/migrations/0012_auto_20211206_1347.py +++ b/src/ralph/operations/migrations/0012_auto_20211206_1347.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('operations', '0011_operation_reporter'), + ("operations", "0011_operation_reporter"), ] operations = [ migrations.AlterModelOptions( - name='operationstatus', - options={'verbose_name_plural': 'Operation statuses'}, + name="operationstatus", + options={"verbose_name_plural": "Operation statuses"}, ), ] diff --git a/src/ralph/operations/migrations/0013_auto_20240621_1200.py b/src/ralph/operations/migrations/0013_auto_20240621_1200.py index 54a163f36d..da69c453a6 100644 --- a/src/ralph/operations/migrations/0013_auto_20240621_1200.py +++ b/src/ralph/operations/migrations/0013_auto_20240621_1200.py @@ -6,25 +6,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('operations', '0012_auto_20211206_1347'), + ("operations", "0012_auto_20211206_1347"), ] operations = [ migrations.AlterField( - model_name='operationtype', - name='level', + model_name="operationtype", + name="level", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='operationtype', - name='lft', + model_name="operationtype", + name="lft", field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name='operationtype', - name='rght', + model_name="operationtype", + name="rght", field=models.PositiveIntegerField(editable=False), ), ] diff --git a/src/ralph/operations/migrations/0013_auto_20241002_1122.py b/src/ralph/operations/migrations/0013_auto_20241002_1122.py index 1059ca0616..4304ce9b4b 100644 --- a/src/ralph/operations/migrations/0013_auto_20241002_1122.py +++ b/src/ralph/operations/migrations/0013_auto_20241002_1122.py @@ -7,15 +7,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('operations', '0012_auto_20211206_1347'), + ("operations", "0012_auto_20211206_1347"), ] operations = [ migrations.AlterField( - model_name='operation', - name='base_objects', - field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField(blank=True, related_name='operations', to='assets.BaseObject', verbose_name='objects'), + model_name="operation", + name="base_objects", + field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField( + blank=True, + related_name="operations", + to="assets.BaseObject", + verbose_name="objects", + ), ), ] diff --git a/src/ralph/operations/migrations/0014_merge_20241008_1131.py b/src/ralph/operations/migrations/0014_merge_20241008_1131.py index 995ea09c34..5420c1bafb 100644 --- a/src/ralph/operations/migrations/0014_merge_20241008_1131.py +++ b/src/ralph/operations/migrations/0014_merge_20241008_1131.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('operations', '0013_auto_20241002_1122'), - ('operations', '0013_auto_20240621_1200'), + ("operations", "0013_auto_20241002_1122"), + ("operations", "0013_auto_20240621_1200"), ] - operations = [ - ] + operations = [] diff --git a/src/ralph/operations/models.py b/src/ralph/operations/models.py index 2bf268f8ed..7fdb4269c8 100644 --- a/src/ralph/operations/models.py +++ b/src/ralph/operations/models.py @@ -11,95 +11,101 @@ from ralph.assets.models.base import BaseObject from ralph.lib.mixins.fields import TicketIdField -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - TaggableMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TaggableMixin from ralph.lib.polymorphic.fields import PolymorphicManyToManyField class OperationStatus(AdminAbsoluteUrlMixin, NamedMixin, models.Model): class Meta: - verbose_name_plural = _('Operation statuses') + verbose_name_plural = _("Operation statuses") -class OperationType( - AdminAbsoluteUrlMixin, - MPTTModel, - NamedMixin, - models.Model -): +class OperationType(AdminAbsoluteUrlMixin, MPTTModel, NamedMixin, models.Model): parent = TreeForeignKey( - 'self', + "self", null=True, blank=True, - related_name='children', + related_name="children", db_index=True, - on_delete=models.CASCADE + on_delete=models.CASCADE, ) class choices(Choices): _ = Choices.Choice CHANGES = Choices.Group(0) - change = _('change') + change = _("change") INCIDENTS = Choices.Group(100) - incident = _('incident') + incident = _("incident") PROBLEMS = Choices.Group(200) - problem = _('problem') + problem = _("problem") FAILURES = Choices.Group(300) - failure = _('failure') - hardware_failure = _('hardware failure') + failure = _("failure") + hardware_failure = _("hardware failure") class Operation(AdminAbsoluteUrlMixin, TaggableMixin, models.Model): - type = TreeForeignKey(OperationType, verbose_name=_('type'), on_delete=models.CASCADE) + type = TreeForeignKey( + OperationType, verbose_name=_("type"), on_delete=models.CASCADE + ) _allow_in_dashboard = True title = models.CharField( - max_length=350, null=False, blank=False, verbose_name=_('title'), + max_length=350, + null=False, + blank=False, + verbose_name=_("title"), ) description = models.TextField( - verbose_name=_('description'), null=True, blank=True, + verbose_name=_("description"), + null=True, + blank=True, ) status = models.ForeignKey( OperationStatus, - verbose_name=_('status'), + verbose_name=_("status"), null=False, blank=False, - on_delete=models.PROTECT + on_delete=models.PROTECT, ) assignee = models.ForeignKey( settings.AUTH_USER_MODEL, - related_name='operations', - verbose_name=_('assignee'), + related_name="operations", + verbose_name=_("assignee"), null=True, blank=True, on_delete=models.PROTECT, ) reporter = models.ForeignKey( settings.AUTH_USER_MODEL, - related_name='reported_operations', - verbose_name=_('reporter'), + related_name="reported_operations", + verbose_name=_("reporter"), null=True, blank=True, on_delete=models.PROTECT, ) - ticket_id = TicketIdField(unique=True, verbose_name=_('ticket id')) + ticket_id = TicketIdField(unique=True, verbose_name=_("ticket id")) created_date = models.DateTimeField( - null=True, blank=True, verbose_name=_('created date'), + null=True, + blank=True, + verbose_name=_("created date"), ) update_date = models.DateTimeField( - null=True, blank=True, verbose_name=_('updated date'), + null=True, + blank=True, + verbose_name=_("updated date"), ) resolved_date = models.DateTimeField( - null=True, blank=True, verbose_name=_('resolved date'), + null=True, + blank=True, + verbose_name=_("resolved date"), ) base_objects = PolymorphicManyToManyField( - BaseObject, related_name='operations', verbose_name=_('objects'), + BaseObject, + related_name="operations", + verbose_name=_("objects"), blank=True, ) @@ -107,7 +113,7 @@ class Operation(AdminAbsoluteUrlMixin, TaggableMixin, models.Model): @property def ticket_url(self): - return '{}{}'.format(settings.ISSUE_TRACKER_URL, self.ticket_id) + return "{}{}".format(settings.ISSUE_TRACKER_URL, self.ticket_id) def __str__(self): return self.title @@ -116,12 +122,10 @@ def clean(self): super().clean() # check if operation type is in valid subtree if self._operation_type_subtree and self.type_id: - type_root = OperationType.objects.get( - pk=self._operation_type_subtree - ) + type_root = OperationType.objects.get(pk=self._operation_type_subtree) if not self.type.is_descendant_of(type_root, include_self=True): raise ValidationError( - 'Invalid Operation type. Choose descendant of {}'.format( + "Invalid Operation type. Choose descendant of {}".format( self._operation_type_subtree ) ) @@ -131,6 +135,7 @@ class OperationDescendantManager(models.Manager): """ Narrow Operations only to particular type. """ + def __init__(self, descendants_of, *args, **kwargs): self._descendants_of = descendants_of super().__init__(*args, **kwargs) @@ -138,7 +143,7 @@ def __init__(self, descendants_of, *args, **kwargs): @cached_property def type_ids(self): root = OperationType.objects.get(pk=self._descendants_of) - return root.get_descendants(include_self=True).values_list('id') + return root.get_descendants(include_self=True).values_list("id") def get_queryset(self, *args, **kwargs): queryset = super().get_queryset(*args, **kwargs) @@ -183,5 +188,5 @@ def rebuild_handler(sender, **kwargs): Rebuild OperationType tree after migration of operations app. """ # post_migrate is called after each app's migrations - if sender.name == 'ralph.' + OperationType._meta.app_label: + if sender.name == "ralph." + OperationType._meta.app_label: OperationType.objects.rebuild() diff --git a/src/ralph/operations/tests/factories.py b/src/ralph/operations/tests/factories.py index bffc1b148d..4110c31936 100644 --- a/src/ralph/operations/tests/factories.py +++ b/src/ralph/operations/tests/factories.py @@ -11,7 +11,7 @@ Operation, OperationStatus, OperationType, - Problem + Problem, ) @@ -24,28 +24,25 @@ def get_operation_status(name): class OperationTypeFactory(DjangoModelFactory): - - name = factory.Iterator(['Problem', 'Incident', 'Failure', 'Change']) + name = factory.Iterator(["Problem", "Incident", "Failure", "Change"]) class Meta: model = OperationType - django_get_or_create = ['name'] + django_get_or_create = ["name"] class OperationStatusFactory(DjangoModelFactory): - - name = factory.Iterator(['Open', 'Closed', 'Resolved', 'In Progress']) + name = factory.Iterator(["Open", "Closed", "Resolved", "In Progress"]) class Meta: model = OperationStatus - django_get_or_create = ['name'] + django_get_or_create = ["name"] class OperationFactory(DjangoModelFactory): - - title = factory.Sequence(lambda n: 'Operation #%d' % n) - status = factory.LazyAttribute(lambda obj: get_operation_status('Open')) - type = factory.LazyAttribute(lambda obj: get_operation_type('Change')) + title = factory.Sequence(lambda n: "Operation #%d" % n) + status = factory.LazyAttribute(lambda obj: get_operation_status("Open")) + type = factory.LazyAttribute(lambda obj: get_operation_type("Change")) assignee = factory.SubFactory(UserFactory) class Meta: @@ -68,21 +65,21 @@ class Meta: class FailureFactory(OperationFactory): - type = factory.LazyAttribute(lambda obj: get_operation_type('Failure')) + type = factory.LazyAttribute(lambda obj: get_operation_type("Failure")) class Meta: model = Failure class ProblemFactory(OperationFactory): - type = factory.LazyAttribute(lambda obj: get_operation_type('Problem')) + type = factory.LazyAttribute(lambda obj: get_operation_type("Problem")) class Meta: model = Problem class IncidentFactory(OperationFactory): - type = factory.LazyAttribute(lambda obj: get_operation_type('Incident')) + type = factory.LazyAttribute(lambda obj: get_operation_type("Incident")) class Meta: model = Incident diff --git a/src/ralph/operations/tests/test_admin.py b/src/ralph/operations/tests/test_admin.py index edb5159270..774ab83cf8 100644 --- a/src/ralph/operations/tests/test_admin.py +++ b/src/ralph/operations/tests/test_admin.py @@ -1,7 +1,6 @@ from django.test import TestCase from django.urls import reverse -from ralph.operations.models import OperationType from ralph.operations.tests.factories import OperationFactory from ralph.tests.mixins import ClientMixin @@ -11,5 +10,5 @@ def test_operation_changelist_should_run_2_queries(self): OperationFactory.create_batch(5) with self.assertNumQueries(2): self.client.get( - reverse('admin:operations_operation_changelist'), + reverse("admin:operations_operation_changelist"), ) diff --git a/src/ralph/operations/tests/test_api.py b/src/ralph/operations/tests/test_api.py index ca69725b29..a990017561 100644 --- a/src/ralph/operations/tests/test_api.py +++ b/src/ralph/operations/tests/test_api.py @@ -8,64 +8,61 @@ class OperationsAPITestCase(RalphAPITestCase): - fixtures = ['operation_types', 'operation_statuses'] + fixtures = ["operation_types", "operation_statuses"] def test_list_operations(self): num_operations = 10 - operation_title = 'TEST OPERATION' - operation_description = 'TEST DESCRIPTION' + operation_title = "TEST OPERATION" + operation_description = "TEST DESCRIPTION" for i in range(num_operations): - OperationFactory( - title=operation_title, - description=operation_description - ) + OperationFactory(title=operation_title, description=operation_description) - url = reverse('operation-list') - response = self.client.get(url, format='json') + url = reverse("operation-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], num_operations) + self.assertEqual(response.data["count"], num_operations) def test_operation_details(self): op = OperationFactory() - url = reverse('operation-detail', args=(op.id,)) - response = self.client.get(url, format='json') + url = reverse("operation-detail", args=(op.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) received_op = response.data - self.assertEqual(received_op['status'], op.status.name) - self.assertEqual(received_op['title'], op.title) + self.assertEqual(received_op["status"], op.status.name) + self.assertEqual(received_op["title"], op.title) def test_operation_create(self): assignee = UserFactory() reporter = UserFactory() op_data = { - 'title': 'deadbeef-title', - 'description': 'deadbeef-description', - 'status': 'Open', - 'type': 'Change', - 'ticket_id': 'DEADBEEF-42', - 'assignee': assignee.username, - 'reporter': reporter.username + "title": "deadbeef-title", + "description": "deadbeef-description", + "status": "Open", + "type": "Change", + "ticket_id": "DEADBEEF-42", + "assignee": assignee.username, + "reporter": reporter.username, } resp = self.client.post( - reverse('operation-list'), - data=op_data, - format='json', - ) + reverse("operation-list"), + data=op_data, + format="json", + ) self.assertEqual(resp.status_code, 201) - op = Operation.objects.get(ticket_id=op_data['ticket_id']) + op = Operation.objects.get(ticket_id=op_data["ticket_id"]) - self.assertEqual(op_data['title'], op.title) - self.assertEqual(op_data['description'], op.description) - self.assertEqual(op_data['assignee'], op.assignee.username) - self.assertEqual(op_data['reporter'], op.reporter.username) - self.assertEqual(op_data['type'], op.type.name) - self.assertEqual(op_data['status'], op.status.name) + self.assertEqual(op_data["title"], op.title) + self.assertEqual(op_data["description"], op.description) + self.assertEqual(op_data["assignee"], op.assignee.username) + self.assertEqual(op_data["reporter"], op.reporter.username) + self.assertEqual(op_data["type"], op.type.name) + self.assertEqual(op_data["status"], op.status.name) diff --git a/src/ralph/operations/tests/test_event_receiver.py b/src/ralph/operations/tests/test_event_receiver.py index f7e705f581..0b7c67b336 100644 --- a/src/ralph/operations/tests/test_event_receiver.py +++ b/src/ralph/operations/tests/test_event_receiver.py @@ -9,64 +9,65 @@ class ChangesReceiverTestCase(RalphTestCase): - - fixtures = ['operation_types', 'operation_statuses'] + fixtures = ["operation_types", "operation_statuses"] def setUp(self): with open( - path.join(path.dirname(__file__), 'sample_jira_event.json'), 'r' + path.join(path.dirname(__file__), "sample_jira_event.json"), "r" ) as f: self.jira_event = json.load(f) def test_new_event_records_operation(self): receive_chm_event(self.jira_event) - op = Operation.objects.get(ticket_id='SOMEPROJ-42') + op = Operation.objects.get(ticket_id="SOMEPROJ-42") - self.assertEqual('username.fortytwo', op.assignee.username) - self.assertEqual('username.fourtwenty', op.reporter.username) - self.assertEqual('Open', op.status.name) + self.assertEqual("username.fortytwo", op.assignee.username) + self.assertEqual("username.fourtwenty", op.reporter.username) + self.assertEqual("Open", op.status.name) def test_recorded_operation_gets_updated(self): - assignee_bak = self.jira_event['issue']['fields']['assignee'] - self.jira_event['issue']['fields']['assignee'] = None + assignee_bak = self.jira_event["issue"]["fields"]["assignee"] + self.jira_event["issue"]["fields"]["assignee"] = None receive_chm_event(self.jira_event) - op = Operation.objects.get(ticket_id='SOMEPROJ-42') - self.assertEqual('Open', op.status.name) + op = Operation.objects.get(ticket_id="SOMEPROJ-42") + self.assertEqual("Open", op.status.name) self.assertEqual(None, op.assignee) - self.jira_event['issue']['fields']['assignee'] = assignee_bak - self.jira_event['issue']['fields']['status']['name'] = 'Closed' + self.jira_event["issue"]["fields"]["assignee"] = assignee_bak + self.jira_event["issue"]["fields"]["status"]["name"] = "Closed" receive_chm_event(self.jira_event) - op = Operation.objects.get(ticket_id='SOMEPROJ-42') - self.assertEqual('Closed', op.status.name) - self.assertEqual('username.fortytwo', op.assignee.username) + op = Operation.objects.get(ticket_id="SOMEPROJ-42") + self.assertEqual("Closed", op.status.name) + self.assertEqual("username.fortytwo", op.assignee.username) def test_no_record_created_unknown_operation_type(self): - self.jira_event['issue']['fields']['issuetype']['name'] = 'DEADBEEF' + self.jira_event["issue"]["fields"]["issuetype"]["name"] = "DEADBEEF" receive_chm_event(self.jira_event) with self.assertRaises(Operation.DoesNotExist): - Operation.objects.get(ticket_id='SOMEPROJ-42') + Operation.objects.get(ticket_id="SOMEPROJ-42") - @mock.patch('ralph.operations.changemanagement.jira.get_ticket_id', - side_effect=IgnoreOperation()) + @mock.patch( + "ralph.operations.changemanagement.jira.get_ticket_id", + side_effect=IgnoreOperation(), + ) def test_no_record_created_when_IgnoreOperation_is_rised(self, m_get): receive_chm_event(self.jira_event) with self.assertRaises(Operation.DoesNotExist): - Operation.objects.get(ticket_id='SOMEPROJ-42') + Operation.objects.get(ticket_id="SOMEPROJ-42") def test_new_status_created_unknown_operation_status(self): - new_status_name = 'DEADBEEF' + new_status_name = "DEADBEEF" - self.jira_event['issue']['fields']['status']['name'] = new_status_name + self.jira_event["issue"]["fields"]["status"]["name"] = new_status_name receive_chm_event(self.jira_event) - op = Operation.objects.get(ticket_id='SOMEPROJ-42') + op = Operation.objects.get(ticket_id="SOMEPROJ-42") self.assertEqual(new_status_name, op.status.name) diff --git a/src/ralph/operations/tests/test_jira_processor.py b/src/ralph/operations/tests/test_jira_processor.py index 49ecb24e74..b549c6cfdd 100644 --- a/src/ralph/operations/tests/test_jira_processor.py +++ b/src/ralph/operations/tests/test_jira_processor.py @@ -3,84 +3,69 @@ from os import path from ralph.operations.changemanagement import jira -from ralph.operations.changemanagement.exceptions import IgnoreOperation -from ralph.operations.models import OperationStatus from ralph.tests import RalphTestCase class JiraProcessorTestCase(RalphTestCase): - def setUp(self): with open( - path.join(path.dirname(__file__), 'sample_jira_event.json'), 'r' + path.join(path.dirname(__file__), "sample_jira_event.json"), "r" ) as f: self.jira_event = json.load(f) def test_get_assignee_username(self): self.assertEqual( - 'username.fortytwo', - jira.get_assignee_username(self.jira_event) + "username.fortytwo", jira.get_assignee_username(self.jira_event) ) def test_get_assignee_username_no_assignee_returns_none(self): - self.jira_event['issue']['fields']['assignee'] = None + self.jira_event["issue"]["fields"]["assignee"] = None self.assertIsNone(jira.get_assignee_username(self.jira_event)) def test_get_reporter_username(self): self.assertEqual( - 'username.fourtwenty', - jira.get_reporter_username(self.jira_event) + "username.fourtwenty", jira.get_reporter_username(self.jira_event) ) def test_get_reporter_username_no_reporter_returns_none(self): - self.jira_event['issue']['fields']['reporter'] = None + self.jira_event["issue"]["fields"]["reporter"] = None self.assertIsNone(jira.get_reporter_username(self.jira_event)) def test_get_title(self): - self.assertEqual( - 'THIS IS THE SUMMARY', - jira.get_title(self.jira_event) - ) + self.assertEqual("THIS IS THE SUMMARY", jira.get_title(self.jira_event)) def test_get_description(self): - self.assertEqual( - 'THAT IS A TEST TICKET', - jira.get_description(self.jira_event) - ) + self.assertEqual("THAT IS A TEST TICKET", jira.get_description(self.jira_event)) def test_get_create_datetime(self): self.assertEqual( - datetime(2017, 3, 20, 9, 10, 40, 0), - jira.get_creation_date(self.jira_event) + datetime(2017, 3, 20, 9, 10, 40, 0), jira.get_creation_date(self.jira_event) ) def test_get_last_update_datetime(self): self.assertEqual( datetime(2017, 3, 20, 11, 33, 44, 0), - jira.get_last_update_date(self.jira_event) + jira.get_last_update_date(self.jira_event), ) def test_get_resolution_datetime(self): - self.jira_event['issue']['fields']['resolutiondate'] = ( - '2017-03-20T14:10:40.000+0100' + self.jira_event["issue"]["fields"]["resolutiondate"] = ( + "2017-03-20T14:10:40.000+0100" ) self.assertEqual( datetime(2017, 3, 20, 13, 10, 40, 0), - jira.get_resolution_date(self.jira_event) + jira.get_resolution_date(self.jira_event), ) def test_get_resolution_datetime_no_time_returns_none(self): self.assertIsNone(jira.get_resolution_date(self.jira_event)) def test_get_ticket_id(self): - self.assertEqual('SOMEPROJ-42', jira.get_ticket_id(self.jira_event)) + self.assertEqual("SOMEPROJ-42", jira.get_ticket_id(self.jira_event)) def test_get_operation_name(self): - self.assertEqual('Change', jira.get_operation_name(self.jira_event)) + self.assertEqual("Change", jira.get_operation_name(self.jira_event)) def test_get_operation_status(self): - self.assertEqual( - 'Open', - jira.get_operation_status(self.jira_event) - ) + self.assertEqual("Open", jira.get_operation_status(self.jira_event)) diff --git a/src/ralph/operations/tests/test_models.py b/src/ralph/operations/tests/test_models.py index 97d2bc83ec..f6560cc8af 100644 --- a/src/ralph/operations/tests/test_models.py +++ b/src/ralph/operations/tests/test_models.py @@ -7,21 +7,20 @@ class OperationModelsTestCase(RalphTestCase): - fixtures = ['operation_types', 'operation_statuses'] + fixtures = ["operation_types", "operation_statuses"] def setUp(self): self.failure = FailureFactory() def test_wrong_type(self): - self.failure.type = OperationType.objects.get(name='Change') + self.failure.type = OperationType.objects.get(name="Change") with self.assertRaises( - ValidationError, - msg='Invalid Operation type. Choose descendant of Failure' + ValidationError, msg="Invalid Operation type. Choose descendant of Failure" ): self.failure.clean() def test_ticket_id_unique(self): - ticket_id = 'FOO-42' + ticket_id = "FOO-42" ChangeFactory(ticket_id=ticket_id) with self.assertRaises(IntegrityError): diff --git a/src/ralph/operations/views.py b/src/ralph/operations/views.py index 25b5bddb9d..e9f8da2650 100644 --- a/src/ralph/operations/views.py +++ b/src/ralph/operations/views.py @@ -9,28 +9,25 @@ class OperationInline(RalphTabularM2MInline): model = Operation - raw_id_fields = ('assignee', 'reporter') - fields = ['title', 'description', 'reporter', 'type', - 'status', 'ticket_id'] + raw_id_fields = ("assignee", "reporter") + fields = ["title", "description", "reporter", "type", "status", "ticket_id"] extra = 1 - verbose_name = _('Operation') + verbose_name = _("Operation") widgets = { - 'description': forms.Textarea(attrs={'rows': 2, 'cols': 30}), + "description": forms.Textarea(attrs={"rows": 2, "cols": 30}), } def get_formset(self, *args, **kwargs): - kwargs.setdefault('widgets', {}).update(self.widgets) + kwargs.setdefault("widgets", {}).update(self.widgets) return super().get_formset(*args, **kwargs) class OperationInlineReadOnlyForExisting(OperationInline): extra = 0 show_change_link = True - verbose_name_plural = _('Existing Operations') - fields = [ - 'title', 'description', 'reporter', 'type', 'status', 'get_ticket_url' - ] + verbose_name_plural = _("Existing Operations") + fields = ["title", "description", "reporter", "type", "status", "get_ticket_url"] def get_readonly_fields(self, request, obj=None): return self.get_fields(request, obj) @@ -41,16 +38,16 @@ def has_add_permission(self, request): @mark_safe def get_ticket_url(self, obj): return '{ticket_id}'.format( - ticket_url=obj.ticket_url, - ticket_id=obj.ticket_id + ticket_url=obj.ticket_url, ticket_id=obj.ticket_id ) - get_ticket_url.short_description = _('ticket ID') + + get_ticket_url.short_description = _("ticket ID") class OperationInlineAddOnly(OperationInline): can_delete = False - verbose_name_plural = _('Add new Operation') - fields = ['title', 'description', 'type', 'status', 'ticket_id'] + verbose_name_plural = _("Add new Operation") + fields = ["title", "description", "type", "status", "ticket_id"] def has_change_permission(self, request, obj=None): return False @@ -60,8 +57,9 @@ class OperationView(RalphDetailViewAdmin): """ Regular inline (form for new and existing Operations) """ - icon = 'ambulance' - label = _('Operations') + + icon = "ambulance" + label = _("Operations") inlines = [OperationInline] @@ -69,4 +67,5 @@ class OperationViewReadOnlyForExisiting(OperationView): """ Form for adding new Operations, read-only table for exising Operations """ + inlines = [OperationInlineAddOnly, OperationInlineReadOnlyForExisting] diff --git a/src/ralph/reports/__init__.py b/src/ralph/reports/__init__.py index fa5ce8fbdd..83716e90bb 100644 --- a/src/ralph/reports/__init__.py +++ b/src/ralph/reports/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.reports.apps.ReportsConfig' +default_app_config = "ralph.reports.apps.ReportsConfig" diff --git a/src/ralph/reports/admin.py b/src/ralph/reports/admin.py index 6df109fc11..f081503900 100644 --- a/src/ralph/reports/admin.py +++ b/src/ralph/reports/admin.py @@ -12,13 +12,13 @@ class ReportTemplateInline(RalphTabularInline): @register(ReportLanguage) class ReportLanguage(RalphAdmin): - list_display = ['name', 'default'] + list_display = ["name", "default"] @register(Report) class ReportAdmin(RalphAdmin): - search_fields = ('name',) - list_display = ('name', ) + search_fields = ("name",) + list_display = ("name",) inlines = [ ReportTemplateInline, ] diff --git a/src/ralph/reports/apps.py b/src/ralph/reports/apps.py index 1d3a2a1cd0..fc8732dc34 100644 --- a/src/ralph/reports/apps.py +++ b/src/ralph/reports/apps.py @@ -3,5 +3,5 @@ class ReportsConfig(RalphAppConfig): - name = 'ralph.reports' - verbose_name = 'Reports' + name = "ralph.reports" + verbose_name = "Reports" diff --git a/src/ralph/reports/base.py b/src/ralph/reports/base.py index 47c82eb30c..f0d7f1c7c8 100644 --- a/src/ralph/reports/base.py +++ b/src/ralph/reports/base.py @@ -5,8 +5,8 @@ class ReportNode(object): """The basic report node. It is simple object which store name, count, parent and children.""" - def __init__(self, name, count=0, parent=None, children=[], - link=None, **kwargs): + + def __init__(self, name, count=0, parent=None, children=[], link=None, **kwargs): self.name = name self.count = count self.parent = parent @@ -34,17 +34,18 @@ def ancestors(self): def to_dict(self): return { - 'name': self.name, - 'count': self.count, + "name": self.name, + "count": self.count, } def __str__(self): - return '{} ({})'.format(self.name, self.count) + return "{} ({})".format(self.name, self.count) class ReportContainer(list): """Container for nodes. This class provides few helpful methods to manipulate on node set.""" + def get(self, name): return next((node for node in self if node.name == name), None) @@ -84,8 +85,9 @@ def leaves(self): def to_dict(self): def traverse(node): ret = node.to_dict() - ret['children'] = [] + ret["children"] = [] for child in node.children: - ret['children'].append(traverse(child)) + ret["children"].append(traverse(child)) return ret + return [traverse(root) for root in self.roots] diff --git a/src/ralph/reports/factories.py b/src/ralph/reports/factories.py index b807ba544a..c344bb2c2a 100644 --- a/src/ralph/reports/factories.py +++ b/src/ralph/reports/factories.py @@ -6,16 +6,14 @@ class ReportFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'Report {}'.format(n)) + name = factory.Sequence(lambda n: "Report {}".format(n)) class Meta: model = Report class ReportLanguageFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'Report-lang {}'.format(n)) + name = factory.Sequence(lambda n: "Report-lang {}".format(n)) default = False class Meta: @@ -23,8 +21,7 @@ class Meta: class ReportTemplateFactory(DjangoModelFactory): - - template = factory.django.FileField(filename='the_file.dat') + template = factory.django.FileField(filename="the_file.dat") language = factory.SubFactory(ReportLanguageFactory) default = False report = factory.SubFactory(ReportFactory) diff --git a/src/ralph/reports/forms.py b/src/ralph/reports/forms.py index ca5edc31bf..d139bdf984 100644 --- a/src/ralph/reports/forms.py +++ b/src/ralph/reports/forms.py @@ -7,11 +7,7 @@ class ReportTemplateFormset(BaseInlineFormSet): def clean(self): - defaults = [ - row['default'] for row in getattr(self, 'cleaned_data', []) - ] + defaults = [row["default"] for row in getattr(self, "cleaned_data", [])] counted = Counter(defaults)[True] if counted != 1: - raise forms.ValidationError( - _('Please select exactly one default item.') - ) + raise forms.ValidationError(_("Please select exactly one default item.")) diff --git a/src/ralph/reports/helpers.py b/src/ralph/reports/helpers.py index 0c112ba350..765f4ca305 100644 --- a/src/ralph/reports/helpers.py +++ b/src/ralph/reports/helpers.py @@ -17,44 +17,53 @@ def generate_report(name, requester, instances, language, context): if not template: template = report.templates.filter(default=True).first() - template_content = '' - with open(template.template.path, 'rb') as f: + template_content = "" + with open(template.template.path, "rb") as f: template_content = f.read() attachments = [] items_per_attachment = 10 - service_pdf = ExternalService('PDF') + service_pdf = ExternalService("PDF") for n in range(0, len(context), items_per_attachment): # Make sure data is JSON-serializable # Will throw otherwise - data = json.loads(json.dumps( - { - 'id': ', '.join([str(obj.id) for obj in - instances[n:n + items_per_attachment]]), - 'now': str(datetime.datetime.now()), - 'logged_user': obj_to_dict(requester), - 'affected_user': obj_to_dict(instances[0].user), - 'owner': obj_to_dict(instances[0].owner), - 'assets': context[n:n + items_per_attachment], - } - )) - result = service_pdf.run( - template=template_content, - data=data + data = json.loads( + json.dumps( + { + "id": ", ".join( + [str(obj.id) for obj in instances[n : n + items_per_attachment]] + ), + "now": str(datetime.datetime.now()), + "logged_user": obj_to_dict(requester), + "affected_user": obj_to_dict(instances[0].user), + "owner": obj_to_dict(instances[0].owner), + "assets": context[n : n + items_per_attachment], + } + ) ) + result = service_pdf.run(template=template_content, data=data) - filename = "_".join([ - timezone.now().isoformat()[:10], - instances[0].user.get_full_name().lower().replace(' ', '-'), - name, - ]) + '.pdf' + filename = ( + "_".join( + [ + timezone.now().isoformat()[:10], + instances[0].user.get_full_name().lower().replace(" ", "-"), + name, + ] + ) + + ".pdf" + ) with tempfile.TemporaryDirectory() as tmp_dirpath: output_path = os.path.join(tmp_dirpath, filename) - with open(output_path, 'wb') as f: + with open(output_path, "wb") as f: f.write(result) - attachments.append(add_attachment_from_disk( - instances, output_path, requester, - _('Document autogenerated by {} transition.').format(name) - )) + attachments.append( + add_attachment_from_disk( + instances, + output_path, + requester, + _("Document autogenerated by {} transition.").format(name), + ) + ) return attachments diff --git a/src/ralph/reports/management/commands/send_data_center_asset_export.py b/src/ralph/reports/management/commands/send_data_center_asset_export.py index 1fb725845a..01a7b82ac4 100644 --- a/src/ralph/reports/management/commands/send_data_center_asset_export.py +++ b/src/ralph/reports/management/commands/send_data_center_asset_export.py @@ -13,7 +13,7 @@ class Command(BaseCommand): - SUPPORTED_FORMATS = ['.csv', '.xlsx', '.ods'] + SUPPORTED_FORMATS = [".csv", ".xlsx", ".ods"] email_validator = EmailValidator() def add_arguments(self, parser): @@ -23,37 +23,35 @@ def add_arguments(self, parser): "--output-format", type=str, default=".xlsx", - help="Format of the resulting report file" + help="Format of the resulting report file", ) parser.add_argument( - "--recipient-email", - type=str, - help="Recipient's email address" + "--recipient-email", type=str, help="Recipient's email address" ) - parser.add_argument( - "--sender-email", - type=str, - help="Sender's email address" - ) + parser.add_argument("--sender-email", type=str, help="Sender's email address") def handle(self, *args, **options): try: self._validate_options(options) - output_format = options.get('output_format') - recipient_email = options.get('recipient_email') - sender_email = options.get('sender_email') + output_format = options.get("output_format") + recipient_email = options.get("recipient_email") + sender_email = options.get("sender_email") dataset = DataCenterAssetTextResource().export() attachment_content = getattr(dataset, output_format[1:]) attachment_mimetype = mimetypes.types_map[output_format] attachment_filename = "report" + output_format subject = "Ralph Data Center Asset Export" - body = "Attached to this message is a dump " \ - "of Ralph Data Center Assets" + body = "Attached to this message is a dump " "of Ralph Data Center Assets" send_email_with_attachment( - sender_email, recipient_email, subject, body, - attachment_content, attachment_filename, attachment_mimetype + sender_email, + recipient_email, + subject, + body, + attachment_content, + attachment_filename, + attachment_mimetype, ) except Exception: logger.error( @@ -77,22 +75,24 @@ def _validate_options(self, options): checking = "sender-email" self.email_validator(options.get("sender_email", None)) except ValidationError as e: - raise CommandError( - "{}: {}".format(checking, e.message) - ) + raise CommandError("{}: {}".format(checking, e.message)) def send_email_with_attachment( - sender_email, recipient_email, subject, body, attachment_content, + sender_email, + recipient_email, + subject, + body, + attachment_content, attachment_filename, - attachment_mimetype + attachment_mimetype, ): email = EmailMessage( - subject=subject, body=body, from_email=sender_email, - to=[recipient_email] + subject=subject, body=body, from_email=sender_email, to=[recipient_email] ) email.attach( - content=attachment_content, filename=attachment_filename, - mimetype=attachment_mimetype + content=attachment_content, + filename=attachment_filename, + mimetype=attachment_mimetype, ) email.send() diff --git a/src/ralph/reports/migrations/0001_initial.py b/src/ralph/reports/migrations/0001_initial.py index 2bc41cb4cf..f6b244bb7e 100644 --- a/src/ralph/reports/migrations/0001_initial.py +++ b/src/ralph/reports/migrations/0001_initial.py @@ -7,49 +7,119 @@ class Migration(migrations.Migration): - - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Report', + name="Report", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='ReportLanguage', + name="ReportLanguage", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='ReportTemplate', + name="ReportTemplate", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now_add=True)), - ('template', models.FileField(upload_to=ralph.reports.models.get_report_file_path)), - ('default', models.BooleanField()), - ('language', models.ForeignKey(to='reports.ReportLanguage', on_delete=django.db.models.deletion.CASCADE)), - ('report', models.ForeignKey(to='reports.Report', related_name='templates', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "created", + models.DateTimeField(verbose_name="date created", auto_now=True), + ), + ( + "modified", + models.DateTimeField( + verbose_name="last modified", auto_now_add=True + ), + ), + ( + "template", + models.FileField( + upload_to=ralph.reports.models.get_report_file_path + ), + ), + ("default", models.BooleanField()), + ( + "language", + models.ForeignKey( + to="reports.ReportLanguage", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "report", + models.ForeignKey( + to="reports.Report", + related_name="templates", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], ), migrations.AlterUniqueTogether( - name='reporttemplate', - unique_together=set([('language', 'report')]), + name="reporttemplate", + unique_together=set([("language", "report")]), ), ] diff --git a/src/ralph/reports/migrations/0002_auto_20151125_1354.py b/src/ralph/reports/migrations/0002_auto_20151125_1354.py index f552d97e25..7f173419a8 100644 --- a/src/ralph/reports/migrations/0002_auto_20151125_1354.py +++ b/src/ralph/reports/migrations/0002_auto_20151125_1354.py @@ -5,40 +5,39 @@ class Migration(migrations.Migration): - dependencies = [ - ('reports', '0001_initial'), + ("reports", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='report', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="report", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='report', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="report", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='reportlanguage', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="reportlanguage", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='reportlanguage', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="reportlanguage", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), migrations.AlterField( - model_name='reporttemplate', - name='created', - field=models.DateTimeField(auto_now_add=True, verbose_name='date created'), + model_name="reporttemplate", + name="created", + field=models.DateTimeField(auto_now_add=True, verbose_name="date created"), ), migrations.AlterField( - model_name='reporttemplate', - name='modified', - field=models.DateTimeField(auto_now=True, verbose_name='last modified'), + model_name="reporttemplate", + name="modified", + field=models.DateTimeField(auto_now=True, verbose_name="last modified"), ), ] diff --git a/src/ralph/reports/migrations/0003_auto_20151204_0758.py b/src/ralph/reports/migrations/0003_auto_20151204_0758.py index d5756e7d30..755b1f2562 100644 --- a/src/ralph/reports/migrations/0003_auto_20151204_0758.py +++ b/src/ralph/reports/migrations/0003_auto_20151204_0758.py @@ -1,22 +1,21 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('reports', '0002_auto_20151125_1354'), + ("reports", "0002_auto_20151125_1354"), ] operations = [ migrations.AlterModelOptions( - name='report', - options={'ordering': ['name']}, + name="report", + options={"ordering": ["name"]}, ), migrations.AlterModelOptions( - name='reportlanguage', - options={'ordering': ['name']}, + name="reportlanguage", + options={"ordering": ["name"]}, ), ] diff --git a/src/ralph/reports/migrations/0004_reportlanguage_default.py b/src/ralph/reports/migrations/0004_reportlanguage_default.py index 14159aebca..7ee9ace8fc 100644 --- a/src/ralph/reports/migrations/0004_reportlanguage_default.py +++ b/src/ralph/reports/migrations/0004_reportlanguage_default.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('reports', '0003_auto_20151204_0758'), + ("reports", "0003_auto_20151204_0758"), ] operations = [ migrations.AddField( - model_name='reportlanguage', - name='default', + model_name="reportlanguage", + name="default", field=models.BooleanField(default=False), preserve_default=False, ), diff --git a/src/ralph/reports/models.py b/src/ralph/reports/models.py index b6e402fd53..6ef9ffccf4 100644 --- a/src/ralph/reports/models.py +++ b/src/ralph/reports/models.py @@ -3,29 +3,18 @@ from django.utils.translation import ugettext_lazy as _ from ralph.attachments.helpers import get_file_path -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin def get_report_file_path(instance, filename): - return get_file_path( - instance, filename, default_dir='report_templates' - ) + return get_file_path(instance, filename, default_dir="report_templates") class Report(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): pass -class ReportLanguage( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model -): +class ReportLanguage(AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model): default = models.BooleanField() def clean(self): @@ -33,7 +22,7 @@ def clean(self): if self.pk: default_qs = default_qs.exclude(pk=self.pk) if self.default and default_qs.count() > 0: - raise ValidationError(_('Only one language can be default.')) + raise ValidationError(_("Only one language can be default.")) class ReportTemplate(TimeStampMixin, models.Model): @@ -44,16 +33,14 @@ class ReportTemplate(TimeStampMixin, models.Model): language = models.ForeignKey(ReportLanguage, on_delete=models.CASCADE) default = models.BooleanField() report = models.ForeignKey( - Report, - related_name='templates', - on_delete=models.CASCADE + Report, related_name="templates", on_delete=models.CASCADE ) class Meta: - unique_together = ('language', 'report') + unique_together = ("language", "report") def __str__(self): - return '{} ({})'.format(self.template, self.language) + return "{} ({})".format(self.template, self.language) @property def name(self): diff --git a/src/ralph/reports/resources.py b/src/ralph/reports/resources.py index 97167d9c8d..cc3efe629c 100644 --- a/src/ralph/reports/resources.py +++ b/src/ralph/reports/resources.py @@ -5,15 +5,10 @@ from import_export.resources import ModelResource from import_export.widgets import Widget -from ralph.data_center.models import ( - DataCenterAsset, - Orientation, - RackOrientation -) +from ralph.data_center.models import DataCenterAsset, Orientation, RackOrientation class ChoiceWidget(Widget): - def __init__(self, choice: Type[Choices]) -> None: self.choice = choice @@ -21,20 +16,27 @@ def render(self, value, obj=None): if value: return self.choice.from_id(value).name else: - return '' + return "" class ReadonlyField(Field): - - def __init__( - self, attribute=None, column_name=None, widget=None, default=None - ): + def __init__(self, attribute=None, column_name=None, widget=None, default=None): super().__init__(attribute, column_name, widget, default, False) DATA_CENTER_ASSET_FIELDS = ( - 'dc', 'server_room', 'rack', 'rack_orientation', 'orientation', 'position', - 'model', 'hostname', 'management_ip', 'ip', 'barcode', 'sn' + "dc", + "server_room", + "rack", + "rack_orientation", + "orientation", + "position", + "model", + "hostname", + "management_ip", + "ip", + "barcode", + "sn", ) @@ -44,52 +46,31 @@ class DataCenterAssetTextResource(ModelResource): human friendly text form instead of database `id` field of the related object. """ - dc = ReadonlyField( - attribute='rack__server_room__data_center__name' - ) - server_room = ReadonlyField( - attribute='rack__server_room__name' - ) - rack = ReadonlyField( - attribute='rack__name' - ) + + dc = ReadonlyField(attribute="rack__server_room__data_center__name") + server_room = ReadonlyField(attribute="rack__server_room__name") + rack = ReadonlyField(attribute="rack__name") rack_orientation = ReadonlyField( - attribute='rack__orientation', - widget=ChoiceWidget(choice=RackOrientation) + attribute="rack__orientation", widget=ChoiceWidget(choice=RackOrientation) ) orientation = ReadonlyField( - attribute='orientation', - widget=ChoiceWidget(choice=Orientation) - ) - model = ReadonlyField( - attribute='model__name' - ) - management_ip = ReadonlyField( - attribute='management_ip' - ) - ip = ReadonlyField( - attribute='ip' - ) - service_uid = ReadonlyField( - attribute='service_env__service__uid' - ) - service = ReadonlyField( - attribute='service_env__service' - ) - environment = ReadonlyField( - attribute='service_env__environment' - ) - configuration_path = ReadonlyField( - attribute='configuration_path' + attribute="orientation", widget=ChoiceWidget(choice=Orientation) ) + model = ReadonlyField(attribute="model__name") + management_ip = ReadonlyField(attribute="management_ip") + ip = ReadonlyField(attribute="ip") + service_uid = ReadonlyField(attribute="service_env__service__uid") + service = ReadonlyField(attribute="service_env__service") + environment = ReadonlyField(attribute="service_env__environment") + configuration_path = ReadonlyField(attribute="configuration_path") def get_queryset(self): return DataCenterAsset.objects.all().select_related( - 'service_env__service', - 'service_env__environment', - 'rack__server_room__data_center', - 'model', - 'configuration_path', + "service_env__service", + "service_env__environment", + "rack__server_room__data_center", + "model", + "configuration_path", ) class Meta: @@ -103,10 +84,12 @@ def _get_ip(self, dc_asset, is_management=True): # a separate query will be issued here to fetch related `ethernet_set`. # To minimise the number of queries to the possible extent, # `select_related` for `ipaddress` field is used here. - ethernet = dc_asset.ethernet_set.select_related('ipaddress').filter( - ipaddress__is_management=is_management - ).first() - return getattr(ethernet, 'ipaddress', None) + ethernet = ( + dc_asset.ethernet_set.select_related("ipaddress") + .filter(ipaddress__is_management=is_management) + .first() + ) + return getattr(ethernet, "ipaddress", None) def dehydrate_management_ip(self, dc_asset): return str(self._get_ip(dc_asset)) diff --git a/src/ralph/reports/tests/test_email_reports.py b/src/ralph/reports/tests/test_email_reports.py index 13ef8710f6..e3fbef2647 100644 --- a/src/ralph/reports/tests/test_email_reports.py +++ b/src/ralph/reports/tests/test_email_reports.py @@ -8,61 +8,55 @@ from ralph.data_center.tests.factories import DataCenterAssetFactory from ralph.tests import RalphTestCase -EXAMPLE_EMAIL = 'example@example.com' +EXAMPLE_EMAIL = "example@example.com" @ddt class TestEmailReports(RalphTestCase): - def setUp(self): DataCenterAssetFactory.create_batch(10) def call_command( self, - output_format='.csv', + output_format=".csv", recipient_email=EXAMPLE_EMAIL, - sender_email=EXAMPLE_EMAIL + sender_email=EXAMPLE_EMAIL, ): management.call_command( - 'send_data_center_asset_export', + "send_data_center_asset_export", output_format=output_format, recipient_email=recipient_email, - sender_email=sender_email + sender_email=sender_email, ) @unpack @data( ( - {'recipient_email': 'this_is_not_an_email'}, - "recipient-email: Enter a valid email address." + {"recipient_email": "this_is_not_an_email"}, + "recipient-email: Enter a valid email address.", ), ( - {'sender_email': 'this_is_not_an_email'}, - "sender-email: Enter a valid email address." + {"sender_email": "this_is_not_an_email"}, + "sender-email: Enter a valid email address.", ), ) def test_data_center_asset_report_validates_recipient_email( self, command_kwargs, error_message ): with self.assertRaises(CommandError) as error: - self.call_command( - **command_kwargs - ) - self.assertEqual( - error_message, - error - ) + self.call_command(**command_kwargs) + self.assertEqual(error_message, error) - @data('.csv', '.ods', '.xlsx') + @data(".csv", ".ods", ".xlsx") @mock.patch( - 'ralph.reports.management.commands.' - 'send_data_center_asset_export.send_email_with_attachment' + "ralph.reports.management.commands." + "send_data_center_asset_export.send_email_with_attachment" ) def test_data_center_asset_report_expected_formats( self, output_format, send_email_with_attachment ): mimetype = mimetypes.types_map[output_format] - filename = 'report' + output_format + filename = "report" + output_format self.call_command(output_format=output_format) call_args = send_email_with_attachment.call_args[0] diff --git a/src/ralph/reports/tests/test_reports.py b/src/ralph/reports/tests/test_reports.py index 53f251b5fe..79ba14d905 100644 --- a/src/ralph/reports/tests/test_reports.py +++ b/src/ralph/reports/tests/test_reports.py @@ -8,7 +8,7 @@ from ralph.assets.tests.factories import ( CategoryFactory, DataCenterAssetModelFactory, - ManufacturerFactory + ManufacturerFactory, ) from ralph.attachments.models import Attachment, AttachmentItem from ralph.back_office.models import BackOfficeAsset @@ -18,7 +18,7 @@ from ralph.licences.models import BaseObjectLicence from ralph.licences.tests.factories import ( LicenceFactory, - LicenceWithUserAndBaseObjectsFactory + LicenceWithUserAndBaseObjectsFactory, ) from ralph.reports.models import ReportLanguage from ralph.reports.views import ( @@ -26,7 +26,7 @@ AssetSupportsReport, CategoryModelReport, CategoryModelStatusReport, - LicenceRelationsReport + LicenceRelationsReport, ) from ralph.supports.models import BaseObjectsSupport from ralph.supports.tests.factories import SupportFactory @@ -36,7 +36,6 @@ class TestReportCategoryTreeView(ClientMixin, RalphTestCase): - def setUp(self): self.client = self.login_as_user() self._create_models() @@ -46,75 +45,88 @@ def _create_models(self): self.keyboard_model = DataCenterAssetModelFactory( category=CategoryFactory(name="Keyboard"), type=ObjectModelType.data_center, - name='Keyboard1', + name="Keyboard1", ) self.mouse_model = DataCenterAssetModelFactory( category=CategoryFactory(name="Mouse"), type=ObjectModelType.data_center, - name='Mouse1', + name="Mouse1", ) self.pendrive_model = DataCenterAssetModelFactory( category=CategoryFactory(name="Pendrive"), type=ObjectModelType.data_center, - name='Pendrive1', + name="Pendrive1", ) self.model_monitor = DataCenterAssetModelFactory( category=CategoryFactory(name="Monitor"), type=ObjectModelType.data_center, - name='Monitor1', + name="Monitor1", ) self.navigation_model = DataCenterAssetModelFactory( category=CategoryFactory(name="Navigation"), type=ObjectModelType.data_center, - name='Navigation1', + name="Navigation1", ) self.scanner_model = DataCenterAssetModelFactory( category=CategoryFactory(name="Scanner"), type=ObjectModelType.data_center, - name='Scanner1', + name="Scanner1", ) self.shredder_model = DataCenterAssetModelFactory( category=CategoryFactory(name="Shredder"), type=ObjectModelType.data_center, - name='Shredder1', + name="Shredder1", ) def _create_assets(self): - [DataCenterAssetFactory(**{ - 'force_depreciation': False, - 'model': self.keyboard_model - }) for _ in range(6)] - [DataCenterAssetFactory(**{ - 'force_depreciation': False, - 'model': self.mouse_model - }) for _ in range(2)] - [DataCenterAssetFactory(**{ - 'force_depreciation': False, - 'model': self.pendrive_model - }) for _ in range(2)] + [ + DataCenterAssetFactory( + **{"force_depreciation": False, "model": self.keyboard_model} + ) + for _ in range(6) + ] + [ + DataCenterAssetFactory( + **{"force_depreciation": False, "model": self.mouse_model} + ) + for _ in range(2) + ] + [ + DataCenterAssetFactory( + **{"force_depreciation": False, "model": self.pendrive_model} + ) + for _ in range(2) + ] - [DataCenterAssetFactory(**{ - 'force_depreciation': False, - 'model': self.model_monitor - }) for _ in range(2)] - [DataCenterAssetFactory(**{ - 'force_depreciation': False, - 'model': self.navigation_model - }) for _ in range(2)] - [DataCenterAssetFactory(**{ - 'force_depreciation': False, - 'model': self.scanner_model - }) for _ in range(3)] - [DataCenterAssetFactory(**{ - 'force_depreciation': False, - 'model': self.shredder_model - }) for _ in range(3)] + [ + DataCenterAssetFactory( + **{"force_depreciation": False, "model": self.model_monitor} + ) + for _ in range(2) + ] + [ + DataCenterAssetFactory( + **{"force_depreciation": False, "model": self.navigation_model} + ) + for _ in range(2) + ] + [ + DataCenterAssetFactory( + **{"force_depreciation": False, "model": self.scanner_model} + ) + for _ in range(3) + ] + [ + DataCenterAssetFactory( + **{"force_depreciation": False, "model": self.shredder_model} + ) + for _ in range(3) + ] def _get_item(self, data, name): for item in data: - if item['name'] == name: - + if item["name"] == name: return item return None @@ -126,33 +138,33 @@ def _get_report(self, report_class, mode=None): def test_category_model_tree(self): report = self._get_report(CategoryModelReport) - self.assertEqual(self._get_item(report, 'Keyboard')['count'], 6) - self.assertEqual(self._get_item(report, 'Mouse')['count'], 2) - self.assertEqual(self._get_item(report, 'Pendrive')['count'], 2) + self.assertEqual(self._get_item(report, "Keyboard")["count"], 6) + self.assertEqual(self._get_item(report, "Mouse")["count"], 2) + self.assertEqual(self._get_item(report, "Pendrive")["count"], 2) - self.assertEqual(self._get_item(report, 'Monitor')['count'], 2) - self.assertEqual(self._get_item(report, 'Navigation')['count'], 2) - self.assertEqual(self._get_item(report, 'Scanner')['count'], 3) - self.assertEqual(self._get_item(report, 'Shredder')['count'], 3) + self.assertEqual(self._get_item(report, "Monitor")["count"], 2) + self.assertEqual(self._get_item(report, "Navigation")["count"], 2) + self.assertEqual(self._get_item(report, "Scanner")["count"], 3) + self.assertEqual(self._get_item(report, "Shredder")["count"], 3) def test_category_model_status_tree(self): report = self._get_report(CategoryModelStatusReport) - item = self._get_item(report, 'Keyboard')['children'][0]['children'] - self.assertEqual(item[0]['count'], 6) - item = self._get_item(report, 'Mouse')['children'][0]['children'] - self.assertEqual(item[0]['count'], 2) - item = self._get_item(report, 'Pendrive')['children'][0]['children'] - self.assertEqual(item[0]['count'], 2) + item = self._get_item(report, "Keyboard")["children"][0]["children"] + self.assertEqual(item[0]["count"], 6) + item = self._get_item(report, "Mouse")["children"][0]["children"] + self.assertEqual(item[0]["count"], 2) + item = self._get_item(report, "Pendrive")["children"][0]["children"] + self.assertEqual(item[0]["count"], 2) - item = self._get_item(report, 'Monitor')['children'][0]['children'] - self.assertEqual(item[0]['count'], 2) - item = self._get_item(report, 'Navigation')['children'][0]['children'] - self.assertEqual(item[0]['count'], 2) - item = self._get_item(report, 'Scanner')['children'][0]['children'] - self.assertEqual(item[0]['count'], 3) - item = self._get_item(report, 'Shredder')['children'][0]['children'] - self.assertEqual(item[0]['count'], 3) + item = self._get_item(report, "Monitor")["children"][0]["children"] + self.assertEqual(item[0]["count"], 2) + item = self._get_item(report, "Navigation")["children"][0]["children"] + self.assertEqual(item[0]["count"], 2) + item = self._get_item(report, "Scanner")["children"][0]["children"] + self.assertEqual(item[0]["count"], 3) + item = self._get_item(report, "Shredder")["children"][0]["children"] + self.assertEqual(item[0]["count"], 3) class TestReportAssetAndLicence(RalphTestCase): @@ -160,20 +172,20 @@ def setUp(self): self.model = DataCenterAssetModelFactory( category=CategoryFactory(name="Keyboard"), type=ObjectModelType.data_center, - name='Keyboard1', - manufacturer=ManufacturerFactory(name='M1') + name="Keyboard1", + manufacturer=ManufacturerFactory(name="M1"), ) self.dc_1 = DataCenterAssetFactory( force_depreciation=False, model=self.model, ) - self.dc_1.tags.add('tag1', 'tag2') + self.dc_1.tags.add("tag1", "tag2") self.licence = LicenceFactory( number_bought=1, - niw='N/A', - software__name='Project Info', + niw="N/A", + software__name="Project Info", software__asset_type=ObjectModelType.data_center, - region__name='US', + region__name="US", ) BaseObjectLicence.objects.create( licence=self.licence, base_object=self.dc_1.baseobject_ptr @@ -184,71 +196,127 @@ def test_asset_relation(self): report_result = list(asset_relation.prepare(DataCenterAsset)) result = [ [ - 'id', 'niw', 'barcode', 'sn', 'model__category__name', - 'model__manufacturer__name', 'model__name', 'status', - 'service_env__service__name', 'invoice_date', 'invoice_no', - 'hostname', 'rack', 'tags' + "id", + "niw", + "barcode", + "sn", + "model__category__name", + "model__manufacturer__name", + "model__name", + "status", + "service_env__service__name", + "invoice_date", + "invoice_no", + "hostname", + "rack", + "tags", ], [ - str(self.dc_1.id), 'None', self.dc_1.barcode, self.dc_1.sn, - 'Keyboard', 'M1', 'Keyboard1', '1', + str(self.dc_1.id), + "None", + self.dc_1.barcode, + self.dc_1.sn, + "Keyboard", + "M1", + "Keyboard1", + "1", self.dc_1.service_env.service.name, - str(self.dc_1.invoice_date), str(self.dc_1.invoice_no), - self.dc_1.hostname, str(self.dc_1.rack), 'tag1,tag2' - ] + str(self.dc_1.invoice_date), + str(self.dc_1.invoice_no), + self.dc_1.hostname, + str(self.dc_1.rack), + "tag1,tag2", + ], ] self.assertEqual(report_result, result) def test_num_queries_dc(self): licence_relation = LicenceRelationsReport() with self.assertNumQueries(3): - list(licence_relation.prepare( - DataCenterAsset) - ) + list(licence_relation.prepare(DataCenterAsset)) def test_num_queries_bo(self): factory.build_batch(LicenceWithUserAndBaseObjectsFactory, 100) licence_relation = LicenceRelationsReport() with self.assertNumQueries(3): - list(licence_relation.prepare( - BackOfficeAsset) - ) + list(licence_relation.prepare(BackOfficeAsset)) def test_licence_relation(self): licence_relation = LicenceRelationsReport() - report_result = list(licence_relation.prepare( - DataCenterAsset) - ) + report_result = list(licence_relation.prepare(DataCenterAsset)) result = [ [ - 'niw', 'software', 'number_bought', - 'price__amount', 'price__currency', 'invoice_date', - 'invoice_no', 'region', 'id', 'asset__barcode', 'asset__niw', - 'asset__backofficeasset__user__username', - 'asset__backofficeasset__user__first_name', - 'asset__backofficeasset__user__last_name', - 'asset__backofficeasset__owner__username', - 'asset__backofficeasset__owner__first_name', - 'asset__backofficeasset__owner__last_name', - 'asset__backofficeasset__region__name', 'user__username', - 'user__first_name', 'user__last_name', 'single_cost' + "niw", + "software", + "number_bought", + "price__amount", + "price__currency", + "invoice_date", + "invoice_no", + "region", + "id", + "asset__barcode", + "asset__niw", + "asset__backofficeasset__user__username", + "asset__backofficeasset__user__first_name", + "asset__backofficeasset__user__last_name", + "asset__backofficeasset__owner__username", + "asset__backofficeasset__owner__first_name", + "asset__backofficeasset__owner__last_name", + "asset__backofficeasset__region__name", + "user__username", + "user__first_name", + "user__last_name", + "single_cost", ], [ - 'N/A', 'Project Info', '1', - '{0:.2f}'.format(self.licence.price.amount), + "N/A", + "Project Info", + "1", + "{0:.2f}".format(self.licence.price.amount), str(self.licence.price.currency), - str(self.licence.invoice_date), str(self.licence.invoice_no), - 'US', '', '', '', '', '', '', '', '', '', '', '', '', '', '' + str(self.licence.invoice_date), + str(self.licence.invoice_no), + "US", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", ], [ - 'N/A', 'Project Info', '1', - '{0:.2f}'.format(self.licence.price.amount), + "N/A", + "Project Info", + "1", + "{0:.2f}".format(self.licence.price.amount), str(self.licence.price.currency), - str(self.licence.invoice_date), str(self.licence.invoice_no), - 'US', str(self.dc_1.id), self.dc_1.asset.barcode, - 'None', 'None', 'None', 'None', 'None', 'None', 'None', 'None', - '', '', '', '{0:.2f}'.format(self.licence.price.amount) - ] + str(self.licence.invoice_date), + str(self.licence.invoice_no), + "US", + str(self.dc_1.id), + self.dc_1.asset.barcode, + "None", + "None", + "None", + "None", + "None", + "None", + "None", + "None", + "", + "", + "", + "{0:.2f}".format(self.licence.price.amount), + ], ] self.assertEqual(report_result, result) @@ -261,99 +329,112 @@ def setUp(self): self.bo_2 = BackOfficeAssetFactory() self.support = SupportFactory() for obj in [self.dc_1, self.dc_2, self.bo_1, self.bo_2]: - BaseObjectsSupport.objects.create( - support=self.support, baseobject=obj - ) + BaseObjectsSupport.objects.create(support=self.support, baseobject=obj) user = UserFactory() - self.attachment = Attachment.objects.create_from_file_path( - __file__, user - ) + self.attachment = Attachment.objects.create_from_file_path(__file__, user) self.attachment_item = AttachmentItem.objects.attach( - self.support.pk, - get_content_type_for_model(self.support), - [self.attachment] + self.support.pk, get_content_type_for_model(self.support), [self.attachment] ) def test_asset_relation(self): asset_supports = AssetSupportsReport() report_result = list(asset_supports.prepare(DataCenterAsset)) price_per_object = ( - self.support.price.amount - / self.support.baseobjectssupport_set.count() + self.support.price.amount / self.support.baseobjectssupport_set.count() ) result = [ [ - 'baseobject__id', 'baseobject__asset__barcode', - 'baseobject__asset__sn', - 'baseobject__asset__datacenterasset__hostname', - 'baseobject__service_env__service__name', - 'baseobject__asset__invoice_date', - 'baseobject__asset__invoice_no', - 'baseobject__asset__property_of', 'support__name', - 'support__contract_id', 'support__date_to', - 'support__date_from', 'support__invoice_date', - 'support__price__amount', 'support__price__currency', - 'supprt_price_per_object', 'attachments', + "baseobject__id", + "baseobject__asset__barcode", + "baseobject__asset__sn", + "baseobject__asset__datacenterasset__hostname", + "baseobject__service_env__service__name", + "baseobject__asset__invoice_date", + "baseobject__asset__invoice_no", + "baseobject__asset__property_of", + "support__name", + "support__contract_id", + "support__date_to", + "support__date_from", + "support__invoice_date", + "support__price__amount", + "support__price__currency", + "supprt_price_per_object", + "attachments", ], [ - str(self.dc_1.id), self.dc_1.barcode, self.dc_1.sn, - self.dc_1.hostname, self.dc_1.service_env.service.name, - str(self.dc_1.invoice_date), str(self.dc_1.invoice_no), - self.dc_1.property_of.name, self.support.name, - self.support.contract_id, str(self.support.date_to), - str(self.support.date_from), str(self.support.invoice_date), - '{0:.2f}'.format(self.support.price.amount), + str(self.dc_1.id), + self.dc_1.barcode, + self.dc_1.sn, + self.dc_1.hostname, + self.dc_1.service_env.service.name, + str(self.dc_1.invoice_date), + str(self.dc_1.invoice_no), + self.dc_1.property_of.name, + self.support.name, + self.support.contract_id, + str(self.support.date_to), + str(self.support.date_from), + str(self.support.invoice_date), + "{0:.2f}".format(self.support.price.amount), str(self.support.price.currency), - '{0:.2f}'.format(price_per_object), - 'http://127.0.0.1:8000' + reverse('serve_attachment', kwargs={ - 'id': self.attachment.id, - 'filename': self.attachment.original_filename - }) + "{0:.2f}".format(price_per_object), + "http://127.0.0.1:8000" + + reverse( + "serve_attachment", + kwargs={ + "id": self.attachment.id, + "filename": self.attachment.original_filename, + }, + ), ], [ - str(self.dc_2.id), self.dc_2.barcode, self.dc_2.sn, - self.dc_2.hostname, self.dc_2.service_env.service.name, - str(self.dc_2.invoice_date), str(self.dc_2.invoice_no), - self.dc_2.property_of.name, self.support.name, - self.support.contract_id, str(self.support.date_to), - str(self.support.date_from), str(self.support.invoice_date), - '{0:.2f}'.format(self.support.price.amount), + str(self.dc_2.id), + self.dc_2.barcode, + self.dc_2.sn, + self.dc_2.hostname, + self.dc_2.service_env.service.name, + str(self.dc_2.invoice_date), + str(self.dc_2.invoice_no), + self.dc_2.property_of.name, + self.support.name, + self.support.contract_id, + str(self.support.date_to), + str(self.support.date_from), + str(self.support.invoice_date), + "{0:.2f}".format(self.support.price.amount), str(self.support.price.currency), - '{0:.2f}'.format(price_per_object), - 'http://127.0.0.1:8000' + reverse('serve_attachment', kwargs={ - 'id': self.attachment.id, - 'filename': self.attachment.original_filename - }) - ] + "{0:.2f}".format(price_per_object), + "http://127.0.0.1:8000" + + reverse( + "serve_attachment", + kwargs={ + "id": self.attachment.id, + "filename": self.attachment.original_filename, + }, + ), + ], ] self.assertCountEqual(report_result, result) def test_num_queries_dc(self): assets_support_report = AssetSupportsReport() with self.assertNumQueries(5): - list(assets_support_report.prepare( - DataCenterAsset) - ) + list(assets_support_report.prepare(DataCenterAsset)) def test_num_queries_bo(self): assets_support_report = AssetSupportsReport() with self.assertNumQueries(5): - list(assets_support_report.prepare( - BackOfficeAsset) - ) + list(assets_support_report.prepare(BackOfficeAsset)) class TestReportLanguage(RalphTestCase): - def test_clean_metod(self): - ReportLanguage.objects.create(name='pl', default=True) - lang_2 = ReportLanguage.objects.create(name='en', default=False) + ReportLanguage.objects.create(name="pl", default=True) + lang_2 = ReportLanguage.objects.create(name="en", default=False) with self.assertRaisesRegex( - ValidationError, - ( - 'Only one language can be default.' - ) + ValidationError, ("Only one language can be default.") ): lang_2.default = True lang_2.clean() diff --git a/src/ralph/reports/tests/test_resources.py b/src/ralph/reports/tests/test_resources.py index 615be6f01b..1849935c63 100644 --- a/src/ralph/reports/tests/test_resources.py +++ b/src/ralph/reports/tests/test_resources.py @@ -1,46 +1,35 @@ from random import randint -from ralph.assets.tests.factories import ( - DataCenterAssetModelFactory, - EthernetFactory -) +from ralph.assets.tests.factories import DataCenterAssetModelFactory, EthernetFactory from ralph.data_center.models import Orientation, RackOrientation -from ralph.data_center.tests.factories import ( - DataCenterAssetFactory, - RackFactory -) +from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory from ralph.networks.tests.factories import IPAddressFactory from ralph.reports.resources import DataCenterAssetTextResource from ralph.tests import RalphTestCase class TestEmailReports(RalphTestCase): - def setUp(self): self.rack = RackFactory() - self.asset = DataCenterAssetFactory( - rack=self.rack, position=randint(0, 100) - ) - self.ethernets = EthernetFactory.create_batch( - 2, base_object=self.asset - ) + self.asset = DataCenterAssetFactory(rack=self.rack, position=randint(0, 100)) + self.ethernets = EthernetFactory.create_batch(2, base_object=self.asset) self.ip = IPAddressFactory( - base_object=self.asset, is_management=False, - ethernet=self.ethernets[0] + base_object=self.asset, is_management=False, ethernet=self.ethernets[0] ) self.management = IPAddressFactory( - base_object=self.asset, is_management=True, - ethernet=self.ethernets[1] + base_object=self.asset, is_management=True, ethernet=self.ethernets[1] ) def test_dataset_contains_asset_data(self): dataset = DataCenterAssetTextResource().export() - lines = dataset.csv.split('\r\n') + lines = dataset.csv.split("\r\n") - expected_headers = "dc,server_room,rack,rack_orientation," \ - "orientation,position,model,hostname," \ - "management_ip,ip,barcode,sn,service_uid,service," \ - "environment,configuration_path" + expected_headers = ( + "dc,server_room,rack,rack_orientation," + "orientation,position,model,hostname," + "management_ip,ip,barcode,sn,service_uid,service," + "environment,configuration_path" + ) expected_line_data = [ self.rack.server_room.data_center.name, self.rack.server_room.name, @@ -57,9 +46,9 @@ def test_dataset_contains_asset_data(self): self.asset.service_env.service.uid, self.asset.service_env.service.name, self.asset.service_env.environment.name, - self.asset.configuration_path.path + self.asset.configuration_path.path, ] - expected_line = ','.join(expected_line_data) + expected_line = ",".join(expected_line_data) self.assertEqual(expected_headers, lines[0]) self.assertEqual(expected_line, lines[1]) @@ -71,16 +60,12 @@ def test_queries_number(self): asset = DataCenterAssetFactory( rack=rack, position=position, model=model ) - ethernets = EthernetFactory.create_batch( - 2, base_object=asset - ) + ethernets = EthernetFactory.create_batch(2, base_object=asset) IPAddressFactory( - base_object=asset, is_management=False, - ethernet=ethernets[0] + base_object=asset, is_management=False, ethernet=ethernets[0] ) IPAddressFactory( - base_object=asset, is_management=True, - ethernet=ethernets[1] + base_object=asset, is_management=True, ethernet=ethernets[1] ) with self.assertNumQueries(103): DataCenterAssetTextResource().export() diff --git a/src/ralph/reports/urls.py b/src/ralph/reports/urls.py index acfcc9dc25..ff23405ddd 100644 --- a/src/ralph/reports/urls.py +++ b/src/ralph/reports/urls.py @@ -5,43 +5,39 @@ urlpatterns = [ url( - r'^category_model_report/?$', + r"^category_model_report/?$", views.CategoryModelReport.as_view(), - name='category_model_report' + name="category_model_report", ), url( - r'^category_model__status_report/?$', + r"^category_model__status_report/?$", views.CategoryModelStatusReport.as_view(), - name='category_model__status_report' + name="category_model__status_report", ), url( - r'^manufactured_category_model_report/?$', + r"^manufactured_category_model_report/?$", views.ManufacturerCategoryModelReport.as_view(), - name='manufactured_category_model_report' + name="manufactured_category_model_report", ), url( - r'^status_model_report/?$', + r"^status_model_report/?$", views.StatusModelReport.as_view(), - name='status_model_report' + name="status_model_report", ), url( - r'^asset_relations/?$', + r"^asset_relations/?$", views.AssetRelationsReport.as_view(), - name='asset-relations' + name="asset-relations", ), url( - r'^licence_relations/?$', + r"^licence_relations/?$", views.LicenceRelationsReport.as_view(), - name='licence-relations' + name="licence-relations", ), + url(r"^failures_report/?$", views.FailureReport.as_view(), name="failures-report"), url( - r'^failures_report/?$', - views.FailureReport.as_view(), - name='failures-report' - ), - url( - r'^supports_report/?$', + r"^supports_report/?$", views.AssetSupportsReport.as_view(), - name='assets-supports' + name="assets-supports", ), ] diff --git a/src/ralph/reports/views.py b/src/ralph/reports/views.py index 4e3971ce9e..84f20261ac 100644 --- a/src/ralph/reports/views.py +++ b/src/ralph/reports/views.py @@ -24,15 +24,15 @@ logger = logging.getLogger(__name__) -def get_choice_name(choices_class, key, default='------'): +def get_choice_name(choices_class, key, default="------"): """ Return raw name of choice for given key. """ try: return choices_class.from_id(key) if key else default except ValueError: - logger.error('Choice not found for key %s', key) - return 'Does not exist for key {}'.format(key) + logger.error("Choice not found for key %s", key) + return "Does not exist for key {}".format(key) class CSVReportMixin(object): @@ -52,39 +52,33 @@ def get_response(self, request, result): Django response object """ data = tablib.Dataset(*result[1:], headers=result[0]) - response = HttpResponse( - data.csv, - content_type='text/csv;charset=utf-8' - ) - response['Content-Disposition'] = 'attachment;filename={}'.format( - self.filename - ) + response = HttpResponse(data.csv, content_type="text/csv;charset=utf-8") + response["Content-Disposition"] = "attachment;filename={}".format(self.filename) return response class ReportDetail(RalphTemplateView): - - template_name = 'reports/report_detail.html' - default_mode = 'all' + template_name = "reports/report_detail.html" + default_mode = "all" with_modes = True with_datacenters = False with_counter = True links = False modes = [ { - 'name': 'all', - 'verbose_name': _('All'), - 'model': Asset, + "name": "all", + "verbose_name": _("All"), + "model": Asset, }, { - 'name': 'dc', - 'verbose_name': _('Only data center'), - 'model': DataCenterAsset, + "name": "dc", + "verbose_name": _("Only data center"), + "model": DataCenterAsset, }, { - 'name': 'back_office', - 'verbose_name': _('Only back office'), - 'model': BackOfficeAsset, + "name": "back_office", + "verbose_name": _("Only back office"), + "model": BackOfficeAsset, }, ] @@ -99,7 +93,7 @@ def execute(self, model, dc=None): return self.report.roots def prepare(self, model, dc): - raise NotImplemented() + raise NotImplementedError() def is_async(self, request): return False @@ -108,23 +102,24 @@ def is_async(self, request): def datacenters(self): datacenters = [ { - 'name': 'all', - 'verbose_name': 'All', - 'id': 'all', + "name": "all", + "verbose_name": "All", + "id": "all", }, ] return datacenters + [ { - 'name': dc.name.lower(), - 'verbose_name': dc.name, - 'id': dc.id, - } for dc in DataCenter.objects.all() + "name": dc.name.lower(), + "verbose_name": dc.name, + "id": dc.id, + } + for dc in DataCenter.objects.all() ] - def get_model(self, asset_type='all'): + def get_model(self, asset_type="all"): for mode in self.modes: - if mode['name'] == asset_type: - return mode['model'] + if mode["name"] == asset_type: + return mode["model"] return None @property @@ -139,39 +134,39 @@ def get_result(self, request, model, *args, **kwargs): def dispatch(self, request, *args, **kwargs): try: - self.dc = DataCenter.objects.get( - id=request.GET.get('dc', None) - ) + self.dc = DataCenter.objects.get(id=request.GET.get("dc", None)) except (DataCenter.DoesNotExist, ValueError): self.dc = None self.slug = request.resolver_match.url_name - self.asset_type = request.GET.get('asset_type') or self.default_mode + self.asset_type = request.GET.get("asset_type") or self.default_mode return super().dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): context_data = super().get_context_data(**kwargs) - context_data.update({ - 'report': self, - 'subsection': self.name, - 'result': self.execute( - self.get_model(self.asset_type), - self.dc, - ), - 'cache_key': ( - self.asset_type + - (str(self.dc.id) if self.dc else 'all') + - self.slug - ), - 'modes': self.modes, - 'mode': self.asset_type, - 'datacenters': self.datacenters, - 'slug': self.slug, - 'dc': self.dc.id if self.dc else 'all', - }) + context_data.update( + { + "report": self, + "subsection": self.name, + "result": self.execute( + self.get_model(self.asset_type), + self.dc, + ), + "cache_key": ( + self.asset_type + + (str(self.dc.id) if self.dc else "all") + + self.slug + ), + "modes": self.modes, + "mode": self.asset_type, + "datacenters": self.datacenters, + "slug": self.slug, + "dc": self.dc.id if self.dc else "all", + } + ) return context_data def get(self, request, *args, **kwargs): - if request.GET.get('csv'): + if request.GET.get("csv"): model = self.get_model(self.asset_type) return self.get_response(request, self.get_result(request, model)) return super().get(request, *args, **kwargs) @@ -181,7 +176,8 @@ class ReportWithoutAllModeDetail(object): """ Turns off 'All' mode for report. Default mode is 'dc'. """ - default_mode = 'dc' + + default_mode = "dc" @property def modes(self): @@ -189,100 +185,105 @@ def modes(self): class CategoryModelReport(ReportDetail): - - name = _('Category - model') - description = _('Number of assets in each model category.') + name = _("Category - model") + description = _("Number of assets in each model category.") def prepare(self, model, *args, **kwargs): queryset = model.objects - queryset = queryset.select_related('model', 'category').values( - 'model__category__name', - 'model__name', - ).annotate( - num=Count('model') - ).order_by('model__category__name') + queryset = ( + queryset.select_related("model", "category") + .values( + "model__category__name", + "model__name", + ) + .annotate(num=Count("model")) + .order_by("model__category__name") + ) for item in queryset: - cat = item['model__category__name'] or 'None' + cat = item["model__category__name"] or "None" self.report.add( - name=item['model__name'], + name=item["model__name"], parent=cat, - count=item['num'], + count=item["num"], ) class CategoryModelStatusReport(ReportWithoutAllModeDetail, ReportDetail): - - name = _('Category - model - status') - description = _('Number of assets in each status in the model category.') + name = _("Category - model - status") + description = _("Number of assets in each status in the model category.") def prepare(self, model, *args, **kwargs): queryset = model.objects - queryset = queryset.select_related('model', 'category').values( - 'model__category__name', - 'model__name', - 'status', - ).annotate( - num=Count('status') - ).order_by('model__category__name') + queryset = ( + queryset.select_related("model", "category") + .values( + "model__category__name", + "model__name", + "status", + ) + .annotate(num=Count("status")) + .order_by("model__category__name") + ) # get status class dynamically for BO/DC Asset - status_class = model._meta.get_field('status').choices.__class__ + status_class = model._meta.get_field("status").choices.__class__ for item in queryset: - parent = item['model__category__name'] or 'Without category' - name = item['model__name'] + parent = item["model__category__name"] or "Without category" + name = item["model__name"] node, __ = self.report.add( name=name, parent=parent, ) self.report.add( - name=get_choice_name(status_class, item['status']), + name=get_choice_name(status_class, item["status"]), parent=node, - count=item['num'], - unique=False + count=item["num"], + unique=False, ) class ManufacturerCategoryModelReport(ReportDetail): - - name = _('Manufactured - category - model') - description = _('Number of assets in each manufacturer.') + name = _("Manufactured - category - model") + description = _("Number of assets in each manufacturer.") def prepare(self, model, *args, **kwargs): queryset = AssetModel.objects - if model._meta.object_name == 'BackOfficeAsset': + if model._meta.object_name == "BackOfficeAsset": queryset = queryset.filter(type=ObjectModelType.back_office) - if model._meta.object_name == 'DataCenterAsset': + if model._meta.object_name == "DataCenterAsset": queryset = queryset.filter(type=ObjectModelType.data_center) - queryset = queryset.select_related( - 'manufacturer', - 'category', - ).values( - 'manufacturer__name', - 'category__name', - 'name', - ).annotate( - num=Count('assets') - ).order_by('manufacturer__name') + queryset = ( + queryset.select_related( + "manufacturer", + "category", + ) + .values( + "manufacturer__name", + "category__name", + "name", + ) + .annotate(num=Count("assets")) + .order_by("manufacturer__name") + ) for item in queryset: - manufacturer = item['manufacturer__name'] or 'Without manufacturer' + manufacturer = item["manufacturer__name"] or "Without manufacturer" node, __ = self.report.add( - name=item['category__name'], + name=item["category__name"], parent=manufacturer, ) self.report.add( - name=item['name'], + name=item["name"], parent=node, - count=item['num'], + count=item["num"], ) class StatusModelReport(ReportWithoutAllModeDetail, ReportDetail): - with_datacenters = True - name = _('Status - model') - description = _('Number of assets in each the asset status.') + name = _("Status - model") + description = _("Number of assets in each the asset status.") def prepare(self, model, dc=None): queryset = model.objects @@ -290,68 +291,104 @@ def prepare(self, model, dc=None): queryset = queryset.filter(rack__server_room__data_center=dc) queryset = queryset.values( - 'status', - 'model__name', - ).annotate( - num=Count('model') - ) + "status", + "model__name", + ).annotate(num=Count("model")) # get status class dynamically for BO/DC Asset - status_class = model._meta.get_field('status').choices.__class__ + status_class = model._meta.get_field("status").choices.__class__ for item in queryset: self.report.add( - name=item['model__name'], - count=item['num'], - parent=get_choice_name(status_class, item['status']), + name=item["model__name"], + count=item["num"], + parent=get_choice_name(status_class, item["status"]), unique=False, ) -class BaseRelationsReport( - ReportWithoutAllModeDetail, ReportDetail, CSVReportMixin -): - - template_name = 'reports/report_relations.html' +class BaseRelationsReport(ReportWithoutAllModeDetail, ReportDetail, CSVReportMixin): + template_name = "reports/report_relations.html" with_modes = True links = False class AssetRelationsReport(BaseRelationsReport): - name = _('Asset - relations') - description = _('Asset list of information about the user, owner, model.') - filename = 'asset_relations.csv' - extra_headers = ['tags'] + name = _("Asset - relations") + description = _("Asset list of information about the user, owner, model.") + filename = "asset_relations.csv" + extra_headers = ["tags"] dc_headers = [ - 'id', 'niw', 'barcode', 'sn', 'model__category__name', - 'model__manufacturer__name', 'model__name', - 'status', 'service_env__service__name', - 'invoice_date', 'invoice_no', 'hostname', 'rack' + "id", + "niw", + "barcode", + "sn", + "model__category__name", + "model__manufacturer__name", + "model__name", + "status", + "service_env__service__name", + "invoice_date", + "invoice_no", + "hostname", + "rack", ] dc_select_related = [ - 'model', 'model__category', 'service_env', 'service_env__service', - 'model__manufacturer', 'rack', 'rack__server_room', - 'rack__server_room__data_center' + "model", + "model__category", + "service_env", + "service_env__service", + "model__manufacturer", + "rack", + "rack__server_room", + "rack__server_room__data_center", ] bo_headers = [ - 'id', 'niw', 'barcode', 'sn', 'model__category__name', - 'model__manufacturer__name', 'model__name', - 'price__amount', 'price__currency', 'remarks', - 'service_env', 'user__username', 'user__first_name', - 'user__last_name', 'owner__username', 'owner__first_name', - 'owner__last_name', 'owner__company', 'owner__segment', 'status', - 'office_infrastructure__name', 'property_of', 'warehouse__name', - 'invoice_date', 'invoice_no', 'region__name', 'hostname', - 'depreciation_rate', 'buyout_date', + "id", + "niw", + "barcode", + "sn", + "model__category__name", + "model__manufacturer__name", + "model__name", + "price__amount", + "price__currency", + "remarks", + "service_env", + "user__username", + "user__first_name", + "user__last_name", + "owner__username", + "owner__first_name", + "owner__last_name", + "owner__company", + "owner__segment", + "status", + "office_infrastructure__name", + "property_of", + "warehouse__name", + "invoice_date", + "invoice_no", + "region__name", + "hostname", + "depreciation_rate", + "buyout_date", ] bo_select_related = [ - 'model', 'model__category', 'office_infrastructure', 'warehouse', - 'user', 'owner', 'model__manufacturer', 'region', 'property_of' + "model", + "model__category", + "office_infrastructure", + "warehouse", + "user", + "owner", + "model__manufacturer", + "region", + "property_of", ] def prepare(self, model, *args, **kwargs): - queryset = model.objects.prefetch_related('tags') + queryset = model.objects.prefetch_related("tags") headers = self.bo_headers select_related = self.bo_select_related - if model._meta.object_name == 'DataCenterAsset': + if model._meta.object_name == "DataCenterAsset": headers = self.dc_headers select_related = self.dc_select_related @@ -371,56 +408,70 @@ def _get_tags(self, obj): """ Return comma-separated list of tags for object """ - return ','.join(sorted(map(str, obj.tags.all()))) + return ",".join(sorted(map(str, obj.tags.all()))) class AssetSupportsReport(BaseRelationsReport): - name = _('Asset - supports') - description = _('Assets with assigned supports') - filename = 'asset_supports.csv' - extra_headers = ['supprt_price_per_object', 'attachments'] + name = _("Asset - supports") + description = _("Assets with assigned supports") + filename = "asset_supports.csv" + extra_headers = ["supprt_price_per_object", "attachments"] # TODO(mkurek): allow for fields aliases in headers (ex. use tuple with # (field_name, header_name)) # TODO(mkurek): unify these reports dc_headers = [ - 'baseobject__id', 'baseobject__asset__barcode', 'baseobject__asset__sn', - 'baseobject__asset__datacenterasset__hostname', - 'baseobject__service_env__service__name', - 'baseobject__asset__invoice_date', 'baseobject__asset__invoice_no', - 'baseobject__asset__property_of', 'support__name', - 'support__contract_id', 'support__date_to', - 'support__date_from', 'support__invoice_date', - 'support__price__amount', 'support__price__currency' + "baseobject__id", + "baseobject__asset__barcode", + "baseobject__asset__sn", + "baseobject__asset__datacenterasset__hostname", + "baseobject__service_env__service__name", + "baseobject__asset__invoice_date", + "baseobject__asset__invoice_no", + "baseobject__asset__property_of", + "support__name", + "support__contract_id", + "support__date_to", + "support__date_from", + "support__invoice_date", + "support__price__amount", + "support__price__currency", ] dc_select_related = [ - 'baseobject__asset__datacenterasset', + "baseobject__asset__datacenterasset", ] bo_headers = [ - 'baseobject__id', 'baseobject__asset__barcode', 'baseobject__asset__sn', - 'baseobject__asset__invoice_date', 'baseobject__asset__invoice_no', - 'baseobject__asset__property_of', 'support__name', - 'support__contract_id', 'support__date_to', - 'support__date_from', 'support__invoice_date', - 'support__price__amount', 'support__price__currency' + "baseobject__id", + "baseobject__asset__barcode", + "baseobject__asset__sn", + "baseobject__asset__invoice_date", + "baseobject__asset__invoice_no", + "baseobject__asset__property_of", + "support__name", + "support__contract_id", + "support__date_to", + "support__date_from", + "support__invoice_date", + "support__price__amount", + "support__price__currency", ] bo_select_related = [ - 'baseobject__asset__backofficeasset', + "baseobject__asset__backofficeasset", ] def prepare(self, model, *args, **kwargs): queryset = BaseObjectsSupport.objects.select_related( - 'support', - 'baseobject__asset__property_of', - 'baseobject__service_env__service' + "support", + "baseobject__asset__property_of", + "baseobject__service_env__service", ).prefetch_related( # AttachmentItem is attached to BaseObject (by content type), # so we need to prefetch attachments through base object of support - 'support__baseobject_ptr__attachments__attachment', - 'support__baseobjectssupport_set', + "support__baseobject_ptr__attachments__attachment", + "support__baseobjectssupport_set", ) headers = [] select_related = [] - if model._meta.object_name == 'DataCenterAsset': + if model._meta.object_name == "DataCenterAsset": headers = self.dc_headers select_related = self.dc_select_related queryset = queryset.filter( @@ -428,7 +479,7 @@ def prepare(self, model, *args, **kwargs): DataCenterAsset ) ) - elif model._meta.object_name == 'BackOfficeAsset': + elif model._meta.object_name == "BackOfficeAsset": headers = self.bo_headers select_related = self.bo_select_related queryset = queryset.filter( @@ -449,7 +500,7 @@ def get_extra_columns(self, obj): """ return [ self._get_supprt_price_per_object(obj.support), - self._get_attachment_urls(obj.support.baseobject_ptr) + self._get_attachment_urls(obj.support.baseobject_ptr), ] def _get_supprt_price_per_object(self, obj): @@ -460,92 +511,102 @@ def _get_supprt_price_per_object(self, obj): # performs additional SQL query. bo_count = len(obj.baseobjectssupport_set.all()) if bo_count > 0 and obj.price and obj.price.amount > 0: - return '{0:.2f}'.format(obj.price.amount / bo_count) - return '0.00' + return "{0:.2f}".format(obj.price.amount / bo_count) + return "0.00" def _get_attachment_urls(self, obj): """ Return semicolon-separated list of attachments for object """ - return '; '.join([ - '{}{}'.format( - settings.RALPH_INSTANCE, - reverse('serve_attachment', kwargs={ - 'id': attachment_item.attachment.id, - 'filename': attachment_item.attachment.original_filename - }) - ) - for attachment_item in obj.attachments.all() - ]) + return "; ".join( + [ + "{}{}".format( + settings.RALPH_INSTANCE, + reverse( + "serve_attachment", + kwargs={ + "id": attachment_item.attachment.id, + "filename": attachment_item.attachment.original_filename, + }, + ), + ) + for attachment_item in obj.attachments.all() + ] + ) class LicenceRelationsReport(BaseRelationsReport): - name = _('Licence - relations') - filename = 'licence_relations.csv' - description = _('List of licenses assigned to assets and users.') + name = _("Licence - relations") + filename = "licence_relations.csv" + description = _("List of licenses assigned to assets and users.") licences_headers = [ - 'niw', 'software', 'number_bought', 'price__amount', 'price__currency', - 'invoice_date', 'invoice_no', 'region', + "niw", + "software", + "number_bought", + "price__amount", + "price__currency", + "invoice_date", + "invoice_no", + "region", ] licences_asset_headers = [ - 'id', 'asset__barcode', 'asset__niw', - 'asset__backofficeasset__user__username', - 'asset__backofficeasset__user__first_name', - 'asset__backofficeasset__user__last_name', - 'asset__backofficeasset__owner__username', - 'asset__backofficeasset__owner__first_name', - 'asset__backofficeasset__owner__last_name', - 'asset__backofficeasset__region__name' - ] - licences_users_headers = [ - 'user__username', 'user__first_name', 'user__last_name' + "id", + "asset__barcode", + "asset__niw", + "asset__backofficeasset__user__username", + "asset__backofficeasset__user__first_name", + "asset__backofficeasset__user__last_name", + "asset__backofficeasset__owner__username", + "asset__backofficeasset__owner__first_name", + "asset__backofficeasset__owner__last_name", + "asset__backofficeasset__region__name", ] + licences_users_headers = ["user__username", "user__first_name", "user__last_name"] def prepare(self, model, *args, **kwargs): - queryset = Licence.objects.select_related('region', 'software') + queryset = Licence.objects.select_related("region", "software") asset_related = [None] - if model._meta.object_name == 'BackOfficeAsset': + if model._meta.object_name == "BackOfficeAsset": queryset = queryset.filter( software__asset_type__in=( - ObjectModelType.back_office, ObjectModelType.all + ObjectModelType.back_office, + ObjectModelType.all, ) ) asset_related = [ - 'base_object__asset', 'base_object__asset__backofficeasset', - 'base_object__asset__backofficeasset__user', - 'base_object__asset__backofficeasset__owner', - 'base_object__asset__backofficeasset__region' + "base_object__asset", + "base_object__asset__backofficeasset", + "base_object__asset__backofficeasset__user", + "base_object__asset__backofficeasset__owner", + "base_object__asset__backofficeasset__region", ] - if model._meta.object_name == 'DataCenterAsset': - queryset = queryset.filter( - software__asset_type=ObjectModelType.data_center - ) + if model._meta.object_name == "DataCenterAsset": + queryset = queryset.filter(software__asset_type=ObjectModelType.data_center) asset_related = [ - 'base_object__asset', - 'base_object__asset__backofficeasset' + "base_object__asset", + "base_object__asset__backofficeasset", ] - fill_empty_assets = [''] * len(self.licences_asset_headers) - fill_empty_licences = [''] * len(self.licences_users_headers) + fill_empty_assets = [""] * len(self.licences_asset_headers) + fill_empty_licences = [""] * len(self.licences_users_headers) - headers = self.licences_headers + self.licences_asset_headers + \ - self.licences_users_headers + ['single_cost'] + headers = ( + self.licences_headers + + self.licences_asset_headers + + self.licences_users_headers + + ["single_cost"] + ) yield headers - queryset = queryset.select_related( - 'software' - ).prefetch_related( + queryset = queryset.select_related("software").prefetch_related( Prefetch( - 'licenceuser_set', - queryset=LicenceUser.objects.select_related('user') + "licenceuser_set", queryset=LicenceUser.objects.select_related("user") ), Prefetch( - 'baseobjectlicence_set', - queryset=BaseObjectLicence.objects.select_related( - *asset_related - ) - ) + "baseobjectlicence_set", + queryset=BaseObjectLicence.objects.select_related(*asset_related), + ), ) for licence in queryset: @@ -555,38 +616,33 @@ def prepare(self, model, *args, **kwargs): ] base_row = row - row = row + fill_empty_assets + fill_empty_licences + [''] + row = row + fill_empty_assets + fill_empty_licences + [""] yield row if licence.number_bought > 0 and licence.price: - single_licence_cost = str( - licence.price.amount / licence.number_bought - ) + single_licence_cost = str(licence.price.amount / licence.number_bought) else: - single_licence_cost = '' + single_licence_cost = "" for asset in licence.baseobjectlicence_set.all(): row = [ smart_str( getattr_dunder(asset.base_object, column), - ) for column in self.licences_asset_headers - ] - yield base_row + row + fill_empty_licences + [ - single_licence_cost + ) + for column in self.licences_asset_headers ] + yield base_row + row + fill_empty_licences + [single_licence_cost] for user in licence.licenceuser_set.all(): row = [ smart_str(getattr_dunder(user, column)) for column in self.licences_users_headers ] - yield base_row + fill_empty_assets + row + [ - single_licence_cost - ] + yield base_row + fill_empty_assets + row + [single_licence_cost] class FailureReport(ReportWithoutAllModeDetail, ReportDetail): with_datacenters = True - name = _('Failures') - description = _('Failure types for each manufacturer.') + name = _("Failures") + description = _("Failure types for each manufacturer.") def prepare(self, model, dc=None): queryset = model._default_manager @@ -595,22 +651,22 @@ def prepare(self, model, dc=None): operation_types = OperationType.objects.get( pk=OperationType.choices.failure ).get_descendants(include_self=True) - failures = Failure.base_objects.through.objects.filter( - baseobject__in=queryset.all(), - operation__type__in=operation_types - ).values( - 'baseobject__asset__model__manufacturer__name', - 'operation__type__name' - ).annotate( - count=Count('id'), + failures = ( + Failure.base_objects.through.objects.filter( + baseobject__in=queryset.all(), operation__type__in=operation_types + ) + .values( + "baseobject__asset__model__manufacturer__name", "operation__type__name" + ) + .annotate( + count=Count("id"), + ) ) for item in failures: - parent = ( - item['baseobject__asset__model__manufacturer__name'] or 'None' - ) + parent = item["baseobject__asset__model__manufacturer__name"] or "None" self.report.add( - name=item['operation__type__name'], - count=item['count'], + name=item["operation__type__name"], + count=item["count"], parent=parent, unique=False, ) diff --git a/src/ralph/security/__init__.py b/src/ralph/security/__init__.py index 33d34ea4bc..262d6e330d 100644 --- a/src/ralph/security/__init__.py +++ b/src/ralph/security/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.security.apps.SecurityConfig' +default_app_config = "ralph.security.apps.SecurityConfig" diff --git a/src/ralph/security/api.py b/src/ralph/security/api.py index 0575a7a328..97df94014c 100644 --- a/src/ralph/security/api.py +++ b/src/ralph/security/api.py @@ -20,10 +20,10 @@ class Meta: class VulnerabilityViewSet(RalphAPIViewSet): - queryset = Vulnerability.objects.all().prefetch_related('tags') + queryset = Vulnerability.objects.all().prefetch_related("tags") serializer_class = VulnerabilitySerializer filter_fields = [ - 'external_vulnerability_id', + "external_vulnerability_id", ] @@ -36,7 +36,6 @@ class Meta: class SaveSecurityScanSerializer(RalphAPISaveSerializer): - class Meta: model = SecurityScan fields = "__all__" @@ -46,23 +45,22 @@ def to_internal_value(self, data): errors = OrderedDict() # external_id to local_id - if 'external_vulnerabilities' in data: - external_ids = set(data.get('external_vulnerabilities', [])) + if "external_vulnerabilities" in data: + external_ids = set(data.get("external_vulnerabilities", [])) converted = Vulnerability.objects.filter( - external_vulnerability_id__in=external_ids) + external_vulnerability_id__in=external_ids + ) if len(converted) != len(external_ids): unknown = external_ids - set( [str(v.external_vulnerability_id) for v in converted] ) - msg = "Unknow external_vulnerabilities: {}".format( - ', '.join(unknown) - ) - errors['external_vulnerability'] = msg - merged_vulnerabilities = data.get('vulnerabilities', []) + msg = "Unknow external_vulnerabilities: {}".format(", ".join(unknown)) + errors["external_vulnerability"] = msg + merged_vulnerabilities = data.get("vulnerabilities", []) merged_vulnerabilities.extend([c.id for c in converted]) - data['vulnerabilities'] = merged_vulnerabilities + data["vulnerabilities"] = merged_vulnerabilities - host_ip = data.get('host_ip', None) + host_ip = data.get("host_ip", None) if host_ip: base_object = None # try to get base object by IPAddress @@ -73,15 +71,15 @@ def to_internal_value(self, data): else: base_object = ip_address.base_object if not base_object: - errors['host_ip'] = "IP is not assigned to any host" + errors["host_ip"] = "IP is not assigned to any host" else: - errors['host_ip'] = "Host IP is required" + errors["host_ip"] = "Host IP is required" if errors: raise serializers.ValidationError(errors) - data['base_object'] = base_object.pk - data['is_patched'] = not any_exceeded( - Vulnerability.objects.filter(id__in=data['vulnerabilities']) + data["base_object"] = base_object.pk + data["is_patched"] = not any_exceeded( + Vulnerability.objects.filter(id__in=data["vulnerabilities"]) ) result = super().to_internal_value(data) return result @@ -89,12 +87,12 @@ def to_internal_value(self, data): class IPFilter(django_filters.FilterSet): ip = django_filters.CharFilter( - field_name='base_object__ethernet_set__ipaddress__address' + field_name="base_object__ethernet_set__ipaddress__address" ) class Meta: model = IPAddress - fields = ['ip'] + fields = ["ip"] class SecurityScanViewSet(RalphAPIViewSet): @@ -107,8 +105,8 @@ class SecurityScanViewSet(RalphAPIViewSet): @transaction.atomic def create(self, request, *args, **kwargs): - ip = IPAddress.objects.filter(address=self.request.data.get( - 'host_ip', None) + ip = IPAddress.objects.filter( + address=self.request.data.get("host_ip", None) ).first() if ip: # one scan can exist for ip (because there are linked by onetoone) @@ -117,6 +115,6 @@ def create(self, request, *args, **kwargs): return super().create(request, *args, **kwargs) -router.register(r'vulnerabilities', VulnerabilityViewSet) -router.register(r'security-scans', SecurityScanViewSet) +router.register(r"vulnerabilities", VulnerabilityViewSet) +router.register(r"security-scans", SecurityScanViewSet) urlpatterns = [] diff --git a/src/ralph/security/apps.py b/src/ralph/security/apps.py index 3b9de8e00a..767cd8f976 100644 --- a/src/ralph/security/apps.py +++ b/src/ralph/security/apps.py @@ -4,8 +4,8 @@ class SecurityConfig(RalphAppConfig): - name = 'ralph.security' - verbose_name = 'Security' + name = "ralph.security" + verbose_name = "Security" def get_load_modules_when_ready(self): """ @@ -13,4 +13,4 @@ def get_load_modules_when_ready(self): super().get_load_modules_when_ready() when the app is ready. This will add transition actions to appropriate models. """ - return super().get_load_modules_when_ready() + ['transitions'] + return super().get_load_modules_when_ready() + ["transitions"] diff --git a/src/ralph/security/management/commands/update_is_patched.py b/src/ralph/security/management/commands/update_is_patched.py index 49554a4e94..468e68af68 100644 --- a/src/ralph/security/management/commands/update_is_patched.py +++ b/src/ralph/security/management/commands/update_is_patched.py @@ -12,31 +12,26 @@ class Command(BaseCommand): - help = 'Update `is_patched` field on each SecurityScan' + help = "Update `is_patched` field on each SecurityScan" @transaction.atomic def _update_is_patched(self): - - not_patched_ids = SecurityScan.vulnerabilities.through.objects.filter( - vulnerability__patch_deadline__lte=datetime.now() - ).values_list( - 'securityscan_id', flat=True - ).distinct() + not_patched_ids = ( + SecurityScan.vulnerabilities.through.objects.filter( + vulnerability__patch_deadline__lte=datetime.now() + ) + .values_list("securityscan_id", flat=True) + .distinct() + ) # this ones are outdated not_patched = SecurityScan.objects.filter( id__in=not_patched_ids, is_patched=True, - ).update( - is_patched=False - ) + ).update(is_patched=False) - self.stdout.write( - "All scans: {}".format(SecurityScan.objects.count()) - ) - self.stdout.write( - "Scans marked as vulnerable: {}".format(not_patched) - ) + self.stdout.write("All scans: {}".format(SecurityScan.objects.count())) + self.stdout.write("Scans marked as vulnerable: {}".format(not_patched)) def handle(self, **options): self._update_is_patched() diff --git a/src/ralph/security/migrations/0001_initial.py b/src/ralph/security/migrations/0001_initial.py index c282455dd4..c0da9d2f88 100644 --- a/src/ralph/security/migrations/0001_initial.py +++ b/src/ralph/security/migrations/0001_initial.py @@ -7,50 +7,125 @@ class Migration(migrations.Migration): - dependencies = [ - ('taggit', '0002_auto_20150616_2121'), - ('assets', '0008_auto_20160122_1429'), + ("taggit", "0002_auto_20150616_2121"), + ("assets", "0008_auto_20160122_1429"), ] operations = [ migrations.CreateModel( - name='SecurityScan', + name="SecurityScan", fields=[ - ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('last_scan_date', models.DateTimeField()), - ('scan_status', models.PositiveIntegerField(choices=[(1, 'ok'), (2, 'fail'), (3, 'error')])), - ('next_scan_date', models.DateTimeField()), - ('details_url', models.URLField(max_length=255, blank=True)), - ('rescan_url', models.URLField(verbose_name='Rescan url', blank=True)), - ('base_object', models.ForeignKey(to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('tags', taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', verbose_name='Tags', to='taggit.Tag', through='taggit.TaggedItem', blank=True)), + ( + "id", + models.AutoField( + primary_key=True, + verbose_name="ID", + auto_created=True, + serialize=False, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ("last_scan_date", models.DateTimeField()), + ( + "scan_status", + models.PositiveIntegerField( + choices=[(1, "ok"), (2, "fail"), (3, "error")] + ), + ), + ("next_scan_date", models.DateTimeField()), + ("details_url", models.URLField(max_length=255, blank=True)), + ("rescan_url", models.URLField(verbose_name="Rescan url", blank=True)), + ( + "base_object", + models.ForeignKey( + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "tags", + taggit.managers.TaggableManager( + help_text="A comma-separated list of tags.", + verbose_name="Tags", + to="taggit.Tag", + through="taggit.TaggedItem", + blank=True, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='Vulnerability', + name="Vulnerability", fields=[ - ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('name', models.CharField(verbose_name='name', max_length=1024)), - ('patch_deadline', models.DateTimeField(null=True, blank=True)), - ('risk', models.PositiveIntegerField(null=True, choices=[(1, 'low'), (2, 'medium'), (3, 'high')], blank=True)), - ('external_vulnerability_id', models.IntegerField(help_text='Id of vulnerability from external system', unique=True, null=True, blank=True)), - ('tags', taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', verbose_name='Tags', to='taggit.Tag', through='taggit.TaggedItem', blank=True)), + ( + "id", + models.AutoField( + primary_key=True, + verbose_name="ID", + auto_created=True, + serialize=False, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ("name", models.CharField(verbose_name="name", max_length=1024)), + ("patch_deadline", models.DateTimeField(null=True, blank=True)), + ( + "risk", + models.PositiveIntegerField( + null=True, + choices=[(1, "low"), (2, "medium"), (3, "high")], + blank=True, + ), + ), + ( + "external_vulnerability_id", + models.IntegerField( + help_text="Id of vulnerability from external system", + unique=True, + null=True, + blank=True, + ), + ), + ( + "tags", + taggit.managers.TaggableManager( + help_text="A comma-separated list of tags.", + verbose_name="Tags", + to="taggit.Tag", + through="taggit.TaggedItem", + blank=True, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.AddField( - model_name='securityscan', - name='vulnerabilities', - field=models.ManyToManyField(to='security.Vulnerability'), + model_name="securityscan", + name="vulnerabilities", + field=models.ManyToManyField(to="security.Vulnerability"), ), ] diff --git a/src/ralph/security/migrations/0002_auto_20160307_1138.py b/src/ralph/security/migrations/0002_auto_20160307_1138.py index 2f8808e9d4..ee0dd9bc41 100644 --- a/src/ralph/security/migrations/0002_auto_20160307_1138.py +++ b/src/ralph/security/migrations/0002_auto_20160307_1138.py @@ -1,25 +1,36 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.mixins.models class Migration(migrations.Migration): - dependencies = [ - ('security', '0001_initial'), + ("security", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='securityscan', - name='tags', - field=ralph.lib.mixins.models.TaggableManager(blank=True, verbose_name='Tags', help_text='A comma-separated list of tags.', to='taggit.Tag', through='taggit.TaggedItem'), + model_name="securityscan", + name="tags", + field=ralph.lib.mixins.models.TaggableManager( + blank=True, + verbose_name="Tags", + help_text="A comma-separated list of tags.", + to="taggit.Tag", + through="taggit.TaggedItem", + ), ), migrations.AlterField( - model_name='vulnerability', - name='tags', - field=ralph.lib.mixins.models.TaggableManager(blank=True, verbose_name='Tags', help_text='A comma-separated list of tags.', to='taggit.Tag', through='taggit.TaggedItem'), + model_name="vulnerability", + name="tags", + field=ralph.lib.mixins.models.TaggableManager( + blank=True, + verbose_name="Tags", + help_text="A comma-separated list of tags.", + to="taggit.Tag", + through="taggit.TaggedItem", + ), ), ] diff --git a/src/ralph/security/migrations/0003_auto_20170110_1352.py b/src/ralph/security/migrations/0003_auto_20170110_1352.py index 75eb5c1490..e16a32a143 100644 --- a/src/ralph/security/migrations/0003_auto_20170110_1352.py +++ b/src/ralph/security/migrations/0003_auto_20170110_1352.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('security', '0002_auto_20160307_1138'), + ("security", "0002_auto_20160307_1138"), ] operations = [ migrations.AlterField( - model_name='securityscan', - name='vulnerabilities', - field=models.ManyToManyField(blank=True, to='security.Vulnerability'), + model_name="securityscan", + name="vulnerabilities", + field=models.ManyToManyField(blank=True, to="security.Vulnerability"), ), ] diff --git a/src/ralph/security/migrations/0004_auto_20170321_1332.py b/src/ralph/security/migrations/0004_auto_20170321_1332.py index 139b17a1cb..5adc8c6f76 100644 --- a/src/ralph/security/migrations/0004_auto_20170321_1332.py +++ b/src/ralph/security/migrations/0004_auto_20170321_1332.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations from django.db.models import Q @@ -10,23 +10,20 @@ def leave_only_last_security_scan(apps, schema_editor): total_scans = SecurityScan.objects.count() - base_object_ids = set( - SecurityScan.objects.values_list('base_object', flat=True) - ) + base_object_ids = set(SecurityScan.objects.values_list("base_object", flat=True)) for base_object_id in base_object_ids: - last_scan_id = SecurityScan.objects.filter( - base_object_id=base_object_id - ).latest("last_scan_date").id + last_scan_id = ( + SecurityScan.objects.filter(base_object_id=base_object_id) + .latest("last_scan_date") + .id + ) SecurityScan.objects.filter( - Q(base_object_id=base_object_id) & - ~Q(id=last_scan_id) + Q(base_object_id=base_object_id) & ~Q(id=last_scan_id) ).delete() print() print("Total scans: {}".format(total_scans)) - print("Deleted scans: {}".format( - total_scans - SecurityScan.objects.count() - )) + print("Deleted scans: {}".format(total_scans - SecurityScan.objects.count())) def reverse_func(apps, schema_editor): @@ -34,9 +31,8 @@ def reverse_func(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('security', '0003_auto_20170110_1352'), + ("security", "0003_auto_20170110_1352"), ] operations = [ diff --git a/src/ralph/security/migrations/0005_auto_20170322_0902.py b/src/ralph/security/migrations/0005_auto_20170322_0902.py index e8d84a342f..2fde4ed527 100644 --- a/src/ralph/security/migrations/0005_auto_20170322_0902.py +++ b/src/ralph/security/migrations/0005_auto_20170322_0902.py @@ -6,15 +6,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('security', '0004_auto_20170321_1332'), + ("security", "0004_auto_20170321_1332"), ] operations = [ migrations.AlterField( - model_name='securityscan', - name='base_object', - field=models.OneToOneField(to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE), + model_name="securityscan", + name="base_object", + field=models.OneToOneField( + to="assets.BaseObject", on_delete=django.db.models.deletion.CASCADE + ), ), ] diff --git a/src/ralph/security/migrations/0006_securityscan_is_patched.py b/src/ralph/security/migrations/0006_securityscan_is_patched.py index c07de95705..43435bfff4 100644 --- a/src/ralph/security/migrations/0006_securityscan_is_patched.py +++ b/src/ralph/security/migrations/0006_securityscan_is_patched.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('security', '0005_auto_20170322_0902'), + ("security", "0005_auto_20170322_0902"), ] operations = [ migrations.AddField( - model_name='securityscan', - name='is_patched', + model_name="securityscan", + name="is_patched", field=models.BooleanField(default=False), ), ] diff --git a/src/ralph/security/migrations/0007_auto_20170331_0934.py b/src/ralph/security/migrations/0007_auto_20170331_0934.py index 6f0f2797cc..a96563ddc3 100644 --- a/src/ralph/security/migrations/0007_auto_20170331_0934.py +++ b/src/ralph/security/migrations/0007_auto_20170331_0934.py @@ -3,9 +3,7 @@ from datetime import datetime -from django.db import migrations, models -from django.db.models import Count - +from django.db import migrations def update_is_patched(apps, schema_editor): @@ -15,11 +13,13 @@ def update_is_patched(apps, schema_editor): patched = SecurityScan.objects.update(is_patched=True) # mark as not patched - not_patched_ids = SecurityScan.vulnerabilities.through.objects.filter( - vulnerability__patch_deadline__lte=datetime.now() - ).values_list( - 'securityscan_id', flat=True - ).distinct() + not_patched_ids = ( + SecurityScan.vulnerabilities.through.objects.filter( + vulnerability__patch_deadline__lte=datetime.now() + ) + .values_list("securityscan_id", flat=True) + .distinct() + ) not_patched = SecurityScan.objects.filter(id__in=not_patched_ids).update( is_patched=False ) @@ -30,9 +30,8 @@ def update_is_patched(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('security', '0006_securityscan_is_patched'), + ("security", "0006_securityscan_is_patched"), ] operations = [ diff --git a/src/ralph/security/migrations/0008_vulnerability_display_name.py b/src/ralph/security/migrations/0008_vulnerability_display_name.py index 081c64dfb1..9a2ca7223a 100644 --- a/src/ralph/security/migrations/0008_vulnerability_display_name.py +++ b/src/ralph/security/migrations/0008_vulnerability_display_name.py @@ -5,16 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('security', '0007_auto_20170331_0934'), + ("security", "0007_auto_20170331_0934"), ] operations = [ migrations.AddField( - model_name='vulnerability', - name='display_name', - field=models.CharField(verbose_name='display name', default='', max_length=1024), + model_name="vulnerability", + name="display_name", + field=models.CharField( + verbose_name="display name", default="", max_length=1024 + ), preserve_default=False, ), ] diff --git a/src/ralph/security/models.py b/src/ralph/security/models.py index c308a3cfa1..a7d94b585b 100644 --- a/src/ralph/security/models.py +++ b/src/ralph/security/models.py @@ -6,11 +6,7 @@ from django.utils.translation import ugettext_lazy as _ from ralph.assets.models.base import BaseObject -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - TaggableMixin, - TimeStampMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TaggableMixin, TimeStampMixin from ralph.lib.permissions.models import PermByFieldMixin @@ -43,22 +39,15 @@ class Vulnerability( ): _allow_in_dashboard = True - name = models.CharField( - verbose_name=_("name"), - max_length=1024, - unique=False - ) - display_name = models.CharField( - verbose_name=_("display name"), - max_length=1024 - ) + name = models.CharField(verbose_name=_("name"), max_length=1024, unique=False) + display_name = models.CharField(verbose_name=_("display name"), max_length=1024) patch_deadline = models.DateTimeField(null=True, blank=True) risk = models.PositiveIntegerField(choices=Risk(), null=True, blank=True) external_vulnerability_id = models.IntegerField( unique=True, # id means id null=True, blank=True, - help_text=_('Id of vulnerability from external system'), + help_text=_("Id of vulnerability from external system"), ) @property @@ -67,8 +56,7 @@ def is_deadline_exceeded(self): def __str__(self): deadline = ( - self.patch_deadline.strftime('%Y-%m-%d') if - self.patch_deadline else '-' + self.patch_deadline.strftime("%Y-%m-%d") if self.patch_deadline else "-" ) return "{} ({})".format(self.name, deadline) @@ -86,7 +74,7 @@ class SecurityScan( scan_status = models.PositiveIntegerField(choices=ScanStatus()) next_scan_date = models.DateTimeField() details_url = models.URLField(max_length=255, blank=True) - rescan_url = models.URLField(blank=True, verbose_name=_('Rescan url')) + rescan_url = models.URLField(blank=True, verbose_name=_("Rescan url")) base_object = models.OneToOneField( BaseObject, on_delete=models.CASCADE, @@ -108,7 +96,7 @@ def update_is_patched(self): def __str__(self): return "{} {} ({})".format( - self.last_scan_date.strftime('%Y-%m-%d'), + self.last_scan_date.strftime("%Y-%m-%d"), ScanStatus.from_id(self.scan_status).desc, self.base_object.content_type, ) diff --git a/src/ralph/security/tests/factories.py b/src/ralph/security/tests/factories.py index 69b7d731f4..db0a5c9c80 100644 --- a/src/ralph/security/tests/factories.py +++ b/src/ralph/security/tests/factories.py @@ -9,15 +9,14 @@ class SecurityScanFactory(DjangoModelFactory): - class Meta: model = SecurityScan last_scan_date = datetime(2015, 1, 1) scan_status = ScanStatus.ok next_scan_date = datetime(2016, 1, 1) - details_url = 'https://www.example.com/details' - rescan_url = 'https://www.example.com/rescan' + details_url = "https://www.example.com/details" + rescan_url = "https://www.example.com/rescan" base_object = factory.SubFactory(BaseObjectFactory) @factory.post_generation @@ -40,8 +39,7 @@ def vulnerabilities(self, create, extracted, **kwargs): class VulnerabilityFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'vulnserability %d' % n) + name = factory.Sequence(lambda n: "vulnserability %d" % n) patch_deadline = factory.LazyAttribute( lambda o: (datetime.now() + timedelta(days=10)).replace(microsecond=0) ) diff --git a/src/ralph/security/tests/test_api.py b/src/ralph/security/tests/test_api.py index 21b57d83b0..f7a6499411 100644 --- a/src/ralph/security/tests/test_api.py +++ b/src/ralph/security/tests/test_api.py @@ -7,73 +7,61 @@ from ralph.api.tests._base import RalphAPITestCase from ralph.networks.tests.factories import IPAddressFactory from ralph.security.models import Risk, ScanStatus, SecurityScan, Vulnerability -from ralph.security.tests.factories import ( - SecurityScanFactory, - VulnerabilityFactory -) +from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory class SecurityScanAPITests(RalphAPITestCase): - def setUp(self): super().setUp() self.security_scan = SecurityScanFactory() def test_get_security_scan_list(self): - url = reverse('securityscan-list') - response = self.client.get(url, format='json') + url = reverse("securityscan-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], SecurityScan.objects.count() - ) + self.assertEqual(response.data["count"], SecurityScan.objects.count()) def test_get_security_scan_for_ip(self): ip1 = IPAddressFactory(address="192.168.128.1") - self.security_scan1 = SecurityScanFactory( - base_object=ip1.ethernet.base_object - ) + self.security_scan1 = SecurityScanFactory(base_object=ip1.ethernet.base_object) ip2 = IPAddressFactory(address="192.168.128.2") - self.security_scan2 = SecurityScanFactory( - base_object=ip2.ethernet.base_object - ) + self.security_scan2 = SecurityScanFactory(base_object=ip2.ethernet.base_object) response = self.client.get( - reverse('securityscan-list') + '?' + 'ip={}'.format(ip1.address), - format='json' + reverse("securityscan-list") + "?" + "ip={}".format(ip1.address), + format="json", ) - self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data["count"], 1) self.assertTrue( # check if base_object got correct id - response.data['results'][0]['base_object'].endswith( - '/{}/'.format(ip1.base_object.id) + response.data["results"][0]["base_object"].endswith( + "/{}/".format(ip1.base_object.id) ) ) def test_get_security_scan_details(self): - url = reverse('securityscan-detail', args=(self.security_scan.id,)) - response = self.client.get(url, format='json') + url = reverse("securityscan-detail", args=(self.security_scan.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - for field in ['last_scan_date', 'next_scan_date']: + for field in ["last_scan_date", "next_scan_date"]: self.assertEqual( response.data[field], getattr(self.security_scan, field).isoformat(), ) - for field in ['details_url', 'rescan_url']: - self.assertEqual( - response.data[field], getattr(self.security_scan, field) - ) - self.assertEqual(response.data['scan_status'], ScanStatus.ok.name) + for field in ["details_url", "rescan_url"]: + self.assertEqual(response.data[field], getattr(self.security_scan, field)) + self.assertEqual(response.data["scan_status"], ScanStatus.ok.name) self.assertEqual( - response.data['base_object'], - 'http://testserver/api/base-objects/{}/'.format( + response.data["base_object"], + "http://testserver/api/base-objects/{}/".format( self.security_scan.base_object.id - ) + ), ) self.assertEqual( - len(response.data['vulnerabilities']), + len(response.data["vulnerabilities"]), self.security_scan.vulnerabilities.count(), ) self.assertEqual( - response.data['vulnerabilities'][0]['id'], + response.data["vulnerabilities"][0]["id"], self.security_scan.vulnerabilities.all()[0].id, ) @@ -81,144 +69,146 @@ def test_create_security_scan(self): ip = IPAddressFactory(address="192.168.128.10") vulnerability = VulnerabilityFactory() data = { - 'last_scan_date': '2015-01-01T00:00:00', - 'scan_status': ScanStatus.ok.name, - 'next_scan_date': '2016-01-01T00:00:00', - 'details_url': 'https://example.com/scan-deatils', - 'rescan_url': 'https://example.com/rescan-url', - 'host_ip': ip.address, - 'vulnerabilities': [vulnerability.id, ], + "last_scan_date": "2015-01-01T00:00:00", + "scan_status": ScanStatus.ok.name, + "next_scan_date": "2016-01-01T00:00:00", + "details_url": "https://example.com/scan-deatils", + "rescan_url": "https://example.com/rescan-url", + "host_ip": ip.address, + "vulnerabilities": [ + vulnerability.id, + ], } - url = reverse('securityscan-list') - response = self.client.post(url, data, format='json') + url = reverse("securityscan-list") + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - security_scan = SecurityScan.objects.get(pk=response.data['id']) + security_scan = SecurityScan.objects.get(pk=response.data["id"]) self.assertEqual( - security_scan.last_scan_date.isoformat(), data['last_scan_date'] + security_scan.last_scan_date.isoformat(), data["last_scan_date"] ) self.assertEqual(security_scan.scan_status, ScanStatus.ok) self.assertEqual( - security_scan.next_scan_date.isoformat(), data['next_scan_date'] + security_scan.next_scan_date.isoformat(), data["next_scan_date"] ) - self.assertEqual(security_scan.details_url, data['details_url']) - self.assertEqual(security_scan.rescan_url, data['rescan_url']) + self.assertEqual(security_scan.details_url, data["details_url"]) + self.assertEqual(security_scan.rescan_url, data["rescan_url"]) self.assertEqual(security_scan.base_object, ip.base_object) self.assertEqual(security_scan.vulnerabilities.count(), 1) self.assertEqual(security_scan.vulnerabilities.get(), vulnerability) - def test_create_scan_sets_is_patched_false_when_vulnerabilities(self): ip = IPAddressFactory(address="192.168.128.10") vulnerability = VulnerabilityFactory( patch_deadline=datetime.now() - timedelta(days=10) ) data = { - 'last_scan_date': '2015-01-01T00:00:00', - 'scan_status': ScanStatus.ok.name, - 'next_scan_date': '2016-01-01T00:00:00', - 'details_url': 'https://example.com/scan-deatils', - 'rescan_url': 'https://example.com/rescan-url', - 'host_ip': ip.address, - 'vulnerabilities': [vulnerability.id, ], + "last_scan_date": "2015-01-01T00:00:00", + "scan_status": ScanStatus.ok.name, + "next_scan_date": "2016-01-01T00:00:00", + "details_url": "https://example.com/scan-deatils", + "rescan_url": "https://example.com/rescan-url", + "host_ip": ip.address, + "vulnerabilities": [ + vulnerability.id, + ], } - url = reverse('securityscan-list') + url = reverse("securityscan-list") - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual( - SecurityScan.objects.get(pk=response.data['id']).is_patched, + SecurityScan.objects.get(pk=response.data["id"]).is_patched, False, ) def test_create_scan_sets_is_patched_true_when_no_vulnerabilities(self): ip = IPAddressFactory(address="192.168.128.10") data = { - 'last_scan_date': '2015-01-01T00:00:00', - 'scan_status': ScanStatus.ok.name, - 'next_scan_date': '2016-01-01T00:00:00', - 'details_url': 'https://example.com/scan-deatils', - 'rescan_url': 'https://example.com/rescan-url', - 'host_ip': ip.address, - 'vulnerabilities': [], + "last_scan_date": "2015-01-01T00:00:00", + "scan_status": ScanStatus.ok.name, + "next_scan_date": "2016-01-01T00:00:00", + "details_url": "https://example.com/scan-deatils", + "rescan_url": "https://example.com/rescan-url", + "host_ip": ip.address, + "vulnerabilities": [], } - url = reverse('securityscan-list') + url = reverse("securityscan-list") - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual( - SecurityScan.objects.get(pk=response.data['id']).is_patched, + SecurityScan.objects.get(pk=response.data["id"]).is_patched, True, ) def test_patch_security_scan(self): ip = IPAddressFactory(address="192.168.128.66") - url = reverse('securityscan-detail', args=(self.security_scan.id,)) + url = reverse("securityscan-detail", args=(self.security_scan.id,)) vulnerability = VulnerabilityFactory() data = { - 'last_scan_date': ( - datetime.now() + timedelta(days=10) - ).replace(microsecond=0).isoformat(), - 'scan_status': ScanStatus.error.name, - 'next_scan_date': ( - datetime.now() + timedelta(days=15) - ).replace(microsecond=0).isoformat(), - 'details_url': self.security_scan.details_url + '-new', - 'rescan_url': self.security_scan.rescan_url + '-new', - 'host_ip': ip.address, - 'vulnerabilities': [vulnerability.id, ], + "last_scan_date": (datetime.now() + timedelta(days=10)) + .replace(microsecond=0) + .isoformat(), + "scan_status": ScanStatus.error.name, + "next_scan_date": (datetime.now() + timedelta(days=15)) + .replace(microsecond=0) + .isoformat(), + "details_url": self.security_scan.details_url + "-new", + "rescan_url": self.security_scan.rescan_url + "-new", + "host_ip": ip.address, + "vulnerabilities": [ + vulnerability.id, + ], } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.security_scan.refresh_from_db() self.assertEqual( - self.security_scan.last_scan_date.isoformat(), - data['last_scan_date'] + self.security_scan.last_scan_date.isoformat(), data["last_scan_date"] ) self.assertEqual(self.security_scan.scan_status, ScanStatus.error) self.assertEqual( - self.security_scan.next_scan_date.isoformat(), - data['next_scan_date'] + self.security_scan.next_scan_date.isoformat(), data["next_scan_date"] ) - self.assertEqual(self.security_scan.details_url, data['details_url']) - self.assertEqual(self.security_scan.rescan_url, data['rescan_url']) + self.assertEqual(self.security_scan.details_url, data["details_url"]) + self.assertEqual(self.security_scan.rescan_url, data["rescan_url"]) self.assertEqual(self.security_scan.base_object, ip.base_object) self.assertEqual(self.security_scan.vulnerabilities.count(), 1) self.assertEqual( - self.security_scan.vulnerabilities.get(), vulnerability, + self.security_scan.vulnerabilities.get(), + vulnerability, ) def test_posting_scan_replace_old_one_when_scan_already_exists(self): ip = IPAddressFactory(address="192.168.128.66") scan = SecurityScanFactory(base_object=ip.base_object) data = { - 'last_scan_date': ( - datetime.now() + timedelta(days=10) - ).replace(microsecond=0).isoformat(), - 'scan_status': ScanStatus.ok.name, - 'next_scan_date': ( - datetime.now() + timedelta(days=15) - ).replace(microsecond=0).isoformat(), - 'details_url': "http://example.com", - 'rescan_url': "http://example.com", - 'host_ip': ip.address, - 'vulnerabilities': [VulnerabilityFactory().id, ], + "last_scan_date": (datetime.now() + timedelta(days=10)) + .replace(microsecond=0) + .isoformat(), + "scan_status": ScanStatus.ok.name, + "next_scan_date": (datetime.now() + timedelta(days=15)) + .replace(microsecond=0) + .isoformat(), + "details_url": "http://example.com", + "rescan_url": "http://example.com", + "host_ip": ip.address, + "vulnerabilities": [ + VulnerabilityFactory().id, + ], } self.assertEqual( SecurityScan.objects.get(base_object=ip.base_object.id).id, scan.id, ) - response = self.client.post( - reverse('securityscan-list'), - data, - format='json' - ) + response = self.client.post(reverse("securityscan-list"), data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertNotEqual( @@ -228,94 +218,89 @@ def test_posting_scan_replace_old_one_when_scan_already_exists(self): class VulnerabilityAPITests(RalphAPITestCase): - def setUp(self): super().setUp() self.vulnerability = VulnerabilityFactory() def test_get_vulnerability_list(self): - url = reverse('vulnerability-list') - response = self.client.get(url, format='json') + url = reverse("vulnerability-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], Vulnerability.objects.count() - ) + self.assertEqual(response.data["count"], Vulnerability.objects.count()) def test_get_vulnerability_list_query_count(self): VulnerabilityFactory.create_batch(99) - url = reverse('vulnerability-list') + url = reverse("vulnerability-list") with self.assertNumQueries(5): - response = self.client.get(url + "?limit=100", format='json') + response = self.client.get(url + "?limit=100", format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], Vulnerability.objects.count() - ) + self.assertEqual(response.data["count"], Vulnerability.objects.count()) def test_get_vulnerability_details(self): - url = reverse('vulnerability-detail', args=(self.vulnerability.id,)) - response = self.client.get(url, format='json') + url = reverse("vulnerability-detail", args=(self.vulnerability.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.vulnerability.name) + self.assertEqual(response.data["name"], self.vulnerability.name) self.assertEqual( - response.data['patch_deadline'], - self.vulnerability.patch_deadline.replace( - microsecond=0 - ).isoformat(), + response.data["patch_deadline"], + self.vulnerability.patch_deadline.replace(microsecond=0).isoformat(), ) - self.assertEqual(response.data['risk'], Risk.low.name) + self.assertEqual(response.data["risk"], Risk.low.name) self.assertEqual( - response.data['external_vulnerability_id'], + response.data["external_vulnerability_id"], self.vulnerability.external_vulnerability_id, ) def test_create_vulnerability(self): - url = reverse('vulnerability-list') + url = reverse("vulnerability-list") data = { - 'name': "vulnerability name", - 'display_name': "name", - 'patch_deadline': ( - datetime.now() + timedelta(days=10) - ).replace(microsecond=0).isoformat(), - 'risk': Risk.low.name, - 'external_vulnerability_id': 100, + "name": "vulnerability name", + "display_name": "name", + "patch_deadline": (datetime.now() + timedelta(days=10)) + .replace(microsecond=0) + .isoformat(), + "risk": Risk.low.name, + "external_vulnerability_id": 100, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - vulnerability = Vulnerability.objects.get(pk=response.data['id']) - self.assertEqual(vulnerability.name, data['name']) + vulnerability = Vulnerability.objects.get(pk=response.data["id"]) + self.assertEqual(vulnerability.name, data["name"]) self.assertEqual( - vulnerability.patch_deadline.isoformat(), data['patch_deadline'], + vulnerability.patch_deadline.isoformat(), + data["patch_deadline"], ) self.assertEqual(vulnerability.risk, Risk.low) self.assertEqual( - vulnerability.external_vulnerability_id, - data['external_vulnerability_id'] + vulnerability.external_vulnerability_id, data["external_vulnerability_id"] ) def test_patch_vulnerability(self): - url = reverse('vulnerability-detail', args=(self.vulnerability.id,)) + url = reverse("vulnerability-detail", args=(self.vulnerability.id,)) data = { - 'name': self.vulnerability.name + ' new', - 'patch_deadline': ( - self.vulnerability.patch_deadline + timedelta(days=3) - ).replace(microsecond=0).isoformat(), - 'risk': Risk.high.name, - 'external_vulnerability_id': self.vulnerability.external_vulnerability_id + 10 # noqa + "name": self.vulnerability.name + " new", + "patch_deadline": (self.vulnerability.patch_deadline + timedelta(days=3)) + .replace(microsecond=0) + .isoformat(), + "risk": Risk.high.name, + "external_vulnerability_id": self.vulnerability.external_vulnerability_id + + 10, # noqa } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.vulnerability.refresh_from_db() - self.assertEqual(self.vulnerability.name, data['name']) + self.assertEqual(self.vulnerability.name, data["name"]) self.assertEqual( - self.vulnerability.patch_deadline.isoformat(), - data['patch_deadline']) + self.vulnerability.patch_deadline.isoformat(), data["patch_deadline"] + ) self.assertEqual(self.vulnerability.risk, Risk.high) self.assertEqual( self.vulnerability.external_vulnerability_id, - data['external_vulnerability_id']) + data["external_vulnerability_id"], + ) class TestExternalVulnerability(RalphAPITestCase): @@ -324,42 +309,36 @@ def setUp(self): ip = IPAddressFactory(address="192.168.128.10") self.vulnerability = VulnerabilityFactory() self.data = { - 'last_scan_date': '2015-01-01T00:00:00', - 'scan_status': ScanStatus.ok.name, - 'next_scan_date': '2016-01-01T00:00:00', - 'host_ip': ip.address, - 'external_vulnerabilities': [ - self.vulnerability.external_vulnerability_id - ], + "last_scan_date": "2015-01-01T00:00:00", + "scan_status": ScanStatus.ok.name, + "next_scan_date": "2016-01-01T00:00:00", + "host_ip": ip.address, + "external_vulnerabilities": [self.vulnerability.external_vulnerability_id], } def test_create_scan_by_external_id_works(self): response = self.client.post( - reverse('securityscan-list'), self.data, format='json' - ) - security_scan = SecurityScan.objects.get(pk=response.data['id']) - self.assertEqual( - self.vulnerability.id, security_scan.vulnerabilities.get().id + reverse("securityscan-list"), self.data, format="json" ) + security_scan = SecurityScan.objects.get(pk=response.data["id"]) + self.assertEqual(self.vulnerability.id, security_scan.vulnerabilities.get().id) def test_create_scan_by_duplicated_external_id_works(self): - self.data['external_vulnerabilities'] = [ + self.data["external_vulnerabilities"] = [ + self.vulnerability.external_vulnerability_id, self.vulnerability.external_vulnerability_id, - self.vulnerability.external_vulnerability_id ] response = self.client.post( - reverse('securityscan-list'), self.data, format='json' + reverse("securityscan-list"), self.data, format="json" ) - security_scan = SecurityScan.objects.get(pk=response.data['id']) + security_scan = SecurityScan.objects.get(pk=response.data["id"]) self.assertEqual(security_scan.vulnerabilities.count(), 1) - self.assertEqual( - self.vulnerability.id, security_scan.vulnerabilities.get().id - ) + self.assertEqual(self.vulnerability.id, security_scan.vulnerabilities.get().id) def test_create_scan_works_when_both_vulnerabilities_empty(self): - self.data['external_vulnerabilities'] = [] + self.data["external_vulnerabilities"] = [] response = self.client.post( - reverse('securityscan-list'), self.data, format='json' + reverse("securityscan-list"), self.data, format="json" ) - security_scan = SecurityScan.objects.get(pk=response.data['id']) + security_scan = SecurityScan.objects.get(pk=response.data["id"]) self.assertEqual(security_scan.vulnerabilities.count(), 0) diff --git a/src/ralph/security/tests/test_serializers.py b/src/ralph/security/tests/test_serializers.py index 9d0958df91..d14610b74b 100644 --- a/src/ralph/security/tests/test_serializers.py +++ b/src/ralph/security/tests/test_serializers.py @@ -1,18 +1,13 @@ # -*- coding: utf-8 -*- -from django.http.request import QueryDict from rest_framework import serializers from ralph.api.tests._base import RalphAPITestCase from ralph.networks.tests.factories import IPAddressFactory from ralph.security.api import SaveSecurityScanSerializer -from ralph.security.tests.factories import ( - SecurityScanFactory, - VulnerabilityFactory -) +from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory class SaveSecurityScanSerializerTests(RalphAPITestCase): - def setUp(self): super().setUp() self.security_scan = SecurityScanFactory() @@ -22,23 +17,20 @@ def test_external_id_is_converted_to_local(self): vulnerability_1 = VulnerabilityFactory() vulnerability_2 = VulnerabilityFactory() data = { - 'last_scan_date': '2015-01-01T00:00:00', - 'scan_status': 'ok', - 'next_scan_date': '2016-01-01T00:00:00', - 'details_url': 'https://example.com/scan-deatils', - 'rescan_url': 'https://example.com/rescan-url', - 'host_ip': ip.address, - 'vulnerabilities': [vulnerability_1.id], - 'external_vulnerabilities': [ - vulnerability_2.external_vulnerability_id - ], + "last_scan_date": "2015-01-01T00:00:00", + "scan_status": "ok", + "next_scan_date": "2016-01-01T00:00:00", + "details_url": "https://example.com/scan-deatils", + "rescan_url": "https://example.com/rescan-url", + "host_ip": ip.address, + "vulnerabilities": [vulnerability_1.id], + "external_vulnerabilities": [vulnerability_2.external_vulnerability_id], } - scan_serializer = SaveSecurityScanSerializer( - context={'request': None}) + scan_serializer = SaveSecurityScanSerializer(context={"request": None}) deserialized = scan_serializer.to_internal_value(data) self.assertEqual( - deserialized['vulnerabilities'], + deserialized["vulnerabilities"], [vulnerability_1, vulnerability_2], ) @@ -46,16 +38,15 @@ def test_error_raised_when_unknown_external_id(self): ip = IPAddressFactory(address="192.168.128.10") vulnerability = VulnerabilityFactory() data = { - 'last_scan_date': '2015-01-01T00:00:00', - 'scan_status': 'ok', - 'next_scan_date': '2016-01-01T00:00:00', - 'details_url': 'https://example.com/scan-deatils', - 'rescan_url': 'https://example.com/rescan-url', - 'host_ip': ip.address, - 'vulnerabilities': [vulnerability.id], - 'external_vulnerabilities': ['12345678'], + "last_scan_date": "2015-01-01T00:00:00", + "scan_status": "ok", + "next_scan_date": "2016-01-01T00:00:00", + "details_url": "https://example.com/scan-deatils", + "rescan_url": "https://example.com/rescan-url", + "host_ip": ip.address, + "vulnerabilities": [vulnerability.id], + "external_vulnerabilities": ["12345678"], } - scan_serializer = SaveSecurityScanSerializer( - context={'request': None}) + scan_serializer = SaveSecurityScanSerializer(context={"request": None}) with self.assertRaises(serializers.ValidationError): scan_serializer.to_internal_value(data) diff --git a/src/ralph/security/transitions.py b/src/ralph/security/transitions.py index 16041a29e4..0d59b553a6 100644 --- a/src/ralph/security/transitions.py +++ b/src/ralph/security/transitions.py @@ -3,6 +3,7 @@ Transition actions connected with security. """ + from django.db import transaction from django.utils.translation import ugettext_lazy as _ @@ -14,14 +15,11 @@ HOST_MODELS = [DataCenterAsset, CloudHost, VirtualServer] -@transition_action( - verbose_name=_('Cleanup security scans'), - models=HOST_MODELS -) +@transition_action(verbose_name=_("Cleanup security scans"), models=HOST_MODELS) def cleanup_security_scans(cls, instances, **kwargs): with transaction.atomic(): for instance in instances: try: instance.securityscan.delete() except cls.securityscan.RelatedObjectDoesNotExist: - pass + pass diff --git a/src/ralph/security/views.py b/src/ralph/security/views.py index ed53be712f..85a06d759e 100644 --- a/src/ralph/security/views.py +++ b/src/ralph/security/views.py @@ -29,28 +29,28 @@ def _url_name_for_change_view(obj_class, view_name): return None model_admin = ralph_site._registry[obj_class] found_view = None - for change_view in getattr(model_admin, 'change_views', []): - if getattr(change_view, 'name', '') == view_name: + for change_view in getattr(model_admin, "change_views", []): + if getattr(change_view, "name", "") == view_name: found_view = change_view break - return getattr(found_view, 'url_name', None) + return getattr(found_view, "url_name", None) def _linkify(to_linkify, url): - return "{}".format(url, to_linkify) + return '{}'.format(url, to_linkify) class ScanStatusMixin(object): - field_name = _('Security scan') + field_name = _("Security scan") def _to_span(self, css, text): - return'{}'.format(css, text) + return '{}'.format(css, text) def scan_status(self, obj): try: scan = obj.securityscan except ObjectDoesNotExist: - html = self._to_span('', 'No scan') + html = self._to_span("", "No scan") else: if scan.is_ok: if not scan.is_patched: @@ -60,7 +60,7 @@ def scan_status(self, obj): else: html = self._to_span("warning", "Scan failed") - url_name = _url_name_for_change_view(type(obj), 'security_info') + url_name = _url_name_for_change_view(type(obj), "security_info") if not url_name: logger.error("No security view for obj of type: %s", type(obj)) else: @@ -77,7 +77,9 @@ def __init__(self, *args, **kwargs): self.scan_status.__func__.short_description = self.field_name super().__init__(*args, **kwargs) - self.list_select_related += ['securityscan', ] + self.list_select_related += [ + "securityscan", + ] class ScanStatusInTableMixin(ScanStatusMixin): @@ -88,24 +90,30 @@ def __init__(self, *args, **kwargs): @register(Vulnerability) class VulnerabilityAdmin(RalphAdmin): - search_fields = ['name', ] + search_fields = [ + "name", + ] class VulnerabilitiesInline(RalphTabularInline): verbose_name = "Vulnerability" verbose_name_plural = "Vulnerabilities" model = SecurityScan.vulnerabilities.through - raw_id_fields = ('vulnerability',) + raw_id_fields = ("vulnerability",) @register(SecurityScan) class SecurityScan(RalphAdmin): fields = ( - 'last_scan_date', 'scan_status', 'next_scan_date', 'details_url', - 'rescan_url', + "last_scan_date", + "scan_status", + "next_scan_date", + "details_url", + "rescan_url", ) list_select_related = ( - 'base_object', 'base_object__content_type', + "base_object", + "base_object__content_type", ) inlines = [ @@ -114,12 +122,11 @@ class SecurityScan(RalphAdmin): class SecurityInfo(RalphDetailView): - - icon = 'lock' - label = 'Security Info' - name = 'security_info' + icon = "lock" + label = "Security Info" + name = "security_info" url_name = None - template_name = 'security/securityinfo/security_info.html' + template_name = "security/securityinfo/security_info.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -127,5 +134,5 @@ def get_context_data(self, **kwargs): scan = self.object.securityscan except ObjectDoesNotExist: scan = None - context['security_scan'] = scan + context["security_scan"] = scan return context diff --git a/src/ralph/settings/base.py b/src/ralph/settings/base.py index 2fcaa41df1..719c5a022c 100644 --- a/src/ralph/settings/base.py +++ b/src/ralph/settings/base.py @@ -10,16 +10,19 @@ from ralph.settings.hooks import HOOKS_CONFIGURATION # noqa: F401 -SILENCED_SYSTEM_CHECKS = ['models.E006', ] # TODO fix +SILENCED_SYSTEM_CHECKS = [ + "models.E006", +] # TODO fix -def bool_from_env(var, default: bool=False) -> bool: +def bool_from_env(var, default: bool = False) -> bool: """Helper for converting env string into boolean. Returns bool True for string values: '1' or 'true', False otherwise. """ + def str_to_bool(s: str) -> bool: - return s.lower() in ('1', 'true') + return s.lower() in ("1", "true") os_var = os.environ.get(var) if os_var is None: @@ -30,7 +33,7 @@ def str_to_bool(s: str) -> bool: def get_sentinels(sentinels_string): - """ Helper for converting sentinel hosts string into list of tuples. + """Helper for converting sentinel hosts string into list of tuples. sentinel_string must be a string in the following format: :;: @@ -38,330 +41,331 @@ def get_sentinels(sentinels_string): Returns a list of sentinel host and port tuples """ if sentinels_string: - sentinels = sentinels_string.split(';') - result = [tuple(sentinel.split(':')) for sentinel in sentinels] + sentinels = sentinels_string.split(";") + result = [tuple(sentinel.split(":")) for sentinel in sentinels] return result BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) START_TIMESTAMP = datetime.now() -SECRET_KEY = os.environ.get('SECRET_KEY', 'CHANGE_ME') -LOG_FILEPATH = os.environ.get('LOG_FILEPATH', '/tmp/ralph.log') +SECRET_KEY = os.environ.get("SECRET_KEY", "CHANGE_ME") +LOG_FILEPATH = os.environ.get("LOG_FILEPATH", "/tmp/ralph.log") DEBUG = False -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = ["*"] # Only for deployment -RALPH_INSTANCE = os.environ.get('RALPH_INSTANCE', 'http://127.0.0.1:8000') +RALPH_INSTANCE = os.environ.get("RALPH_INSTANCE", "http://127.0.0.1:8000") # Application definition INSTALLED_APPS = ( - 'django.contrib.contenttypes', - 'taggit', - 'django.contrib.auth', - 'ralph.admin', - 'django.contrib.admin', - 'django.contrib.humanize', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django_filters', - 'django_rq', - 'import_export', - 'mptt', - 'reversion', - 'sitetree', - 'ralph.access_cards', - 'ralph.accounts', - 'ralph.accessories', - 'ralph.assets', - 'ralph.attachments', - 'ralph.back_office', - 'ralph.configuration_management', - 'ralph.dashboards', - 'ralph.data_center', - 'ralph.dhcp', - 'ralph.deployment', - 'ralph.licences', - 'ralph.domains', - 'ralph.trade_marks', - 'ralph.sim_cards', - 'ralph.supports', - 'ralph.security', - 'ralph.lib.foundation', - 'ralph.lib.table', - 'ralph.networks', - 'ralph.data_importer', - 'ralph.dc_view', - 'ralph.reports', - 'ralph.virtual', - 'ralph.operations', - 'ralph.lib.external_services', - 'ralph.lib.transitions', - 'ralph.lib.permissions', - 'ralph.lib.custom_fields', - 'ralph.lib.hooks', - 'ralph.notifications', - 'ralph.ssl_certificates', - 'rest_framework', - 'rest_framework.authtoken', - 'taggit_serializer', - 'djmoney', + "django.contrib.contenttypes", + "taggit", + "django.contrib.auth", + "ralph.admin", + "django.contrib.admin", + "django.contrib.humanize", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django_filters", + "django_rq", + "import_export", + "mptt", + "reversion", + "sitetree", + "ralph.access_cards", + "ralph.accounts", + "ralph.accessories", + "ralph.assets", + "ralph.attachments", + "ralph.back_office", + "ralph.configuration_management", + "ralph.dashboards", + "ralph.data_center", + "ralph.dhcp", + "ralph.deployment", + "ralph.licences", + "ralph.domains", + "ralph.trade_marks", + "ralph.sim_cards", + "ralph.supports", + "ralph.security", + "ralph.lib.foundation", + "ralph.lib.table", + "ralph.networks", + "ralph.data_importer", + "ralph.dc_view", + "ralph.reports", + "ralph.virtual", + "ralph.operations", + "ralph.lib.external_services", + "ralph.lib.transitions", + "ralph.lib.permissions", + "ralph.lib.custom_fields", + "ralph.lib.hooks", + "ralph.notifications", + "ralph.ssl_certificates", + "rest_framework", + "rest_framework.authtoken", + "taggit_serializer", + "djmoney", ) MIDDLEWARE = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'ralph.lib.threadlocal.middleware.ThreadLocalMiddleware', - 'ralph.lib.metrics.middlewares.RequestMetricsMiddleware' + "django.middleware.common.CommonMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django.middleware.security.SecurityMiddleware", + "ralph.lib.threadlocal.middleware.ThreadLocalMiddleware", + "ralph.lib.metrics.middlewares.RequestMetricsMiddleware", ) -ROOT_URLCONF = 'ralph.urls' +ROOT_URLCONF = "ralph.urls" URLCONF_MODULES = [ROOT_URLCONF] TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], - 'loaders': [ - ('django.template.loaders.cached.Loader', [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - 'ralph.lib.template.loaders.AppTemplateLoader', - ]), + "loaders": [ + ( + "django.template.loaders.cached.Loader", + [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + "ralph.lib.template.loaders.AppTemplateLoader", + ], + ), ], }, }, ] -WSGI_APPLICATION = 'ralph.wsgi.application' +WSGI_APPLICATION = "ralph.wsgi.application" DEFAULT_DATABASE_OPTIONS = { - 'sql_mode': 'TRADITIONAL', - 'charset': 'utf8', - 'init_command': """ + "sql_mode": "TRADITIONAL", + "charset": "utf8", + "init_command": """ SET default_storage_engine=INNODB; SET character_set_connection=utf8,collation_connection=utf8_unicode_ci; SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; - """ + """, } -DATABASE_OPTIONS_FROM_ENV = os.environ.get('DATABASE_OPTIONS', None) +DATABASE_OPTIONS_FROM_ENV = os.environ.get("DATABASE_OPTIONS", None) DATABASE_OPTIONS = ( json.loads(DATABASE_OPTIONS_FROM_ENV) - if DATABASE_OPTIONS_FROM_ENV else DEFAULT_DATABASE_OPTIONS + if DATABASE_OPTIONS_FROM_ENV + else DEFAULT_DATABASE_OPTIONS ) -DATABASE_SSL_CA = os.environ.get('DATABASE_SSL_CA', None) +DATABASE_SSL_CA = os.environ.get("DATABASE_SSL_CA", None) if DATABASE_SSL_CA: - DATABASE_OPTIONS.update({'ssl': {'ca': DATABASE_SSL_CA}}) + DATABASE_OPTIONS.update({"ssl": {"ca": DATABASE_SSL_CA}}) DATABASES = { - 'default': { - 'ENGINE': os.environ.get('DATABASE_ENGINE', 'django.db.backends.mysql'), # noqa - 'NAME': os.environ.get('DATABASE_NAME', 'ralph_ng'), - 'USER': os.environ.get('DATABASE_USER', 'ralph_ng'), - 'PASSWORD': os.environ.get('DATABASE_PASSWORD', 'ralph_ng') or None, - 'HOST': os.environ.get('DATABASE_HOST', '127.0.0.1'), - 'PORT': os.environ.get('DATABASE_PORT', 3306), - 'OPTIONS': DATABASE_OPTIONS, - 'ATOMIC_REQUESTS': True, - 'TEST': { - 'NAME': 'test_ralph_ng', - } + "default": { + "ENGINE": os.environ.get("DATABASE_ENGINE", "django.db.backends.mysql"), # noqa + "NAME": os.environ.get("DATABASE_NAME", "ralph_ng"), + "USER": os.environ.get("DATABASE_USER", "ralph_ng"), + "PASSWORD": os.environ.get("DATABASE_PASSWORD", "ralph_ng") or None, + "HOST": os.environ.get("DATABASE_HOST", "127.0.0.1"), + "PORT": os.environ.get("DATABASE_PORT", 3306), + "OPTIONS": DATABASE_OPTIONS, + "ATOMIC_REQUESTS": True, + "TEST": { + "NAME": "test_ralph_ng", + }, } } -AUTH_USER_MODEL = 'accounts.RalphUser' -LOGIN_URL = '/login/' +AUTH_USER_MODEL = "accounts.RalphUser" +LOGIN_URL = "/login/" -LANGUAGE_CODE = 'en-us' -LOCALE_PATHS = (os.path.join(BASE_DIR, 'locale'), ) -TIME_ZONE = 'Europe/Warsaw' -USE_I18N = bool_from_env('USE_I18N', True) -USE_L10N = bool_from_env('USE_L10N', True) +LANGUAGE_CODE = "en-us" +LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),) +TIME_ZONE = "Europe/Warsaw" +USE_I18N = bool_from_env("USE_I18N", True) +USE_L10N = bool_from_env("USE_L10N", True) USE_TZ = False -STATIC_URL = '/static/' +STATIC_URL = "/static/" STATICFILES_DIRS = ( - os.path.join(BASE_DIR, 'static'), - os.path.join(BASE_DIR, 'admin', 'static'), -) -STATIC_ROOT = os.environ.get( - 'STATIC_ROOT', os.path.join(BASE_DIR, 'var', 'static') + os.path.join(BASE_DIR, "static"), + os.path.join(BASE_DIR, "admin", "static"), ) +STATIC_ROOT = os.environ.get("STATIC_ROOT", os.path.join(BASE_DIR, "var", "static")) -MEDIA_URL = '/media/' -MEDIA_ROOT = os.environ.get( - 'MEDIA_ROOT', os.path.join(BASE_DIR, 'var', 'media') -) +MEDIA_URL = "/media/" +MEDIA_ROOT = os.environ.get("MEDIA_ROOT", os.path.join(BASE_DIR, "var", "media")) # adapt message's tags to bootstrap MESSAGE_TAGS = { - messages.DEBUG: 'info', - messages.ERROR: 'alert', + messages.DEBUG: "info", + messages.ERROR: "alert", } FILE_UPLOAD_PERMISSIONS = 0o644 -DEFAULT_DEPRECIATION_RATE = int(os.environ.get('DEFAULT_DEPRECIATION_RATE', 25)) # noqa -DEFAULT_LICENCE_DEPRECIATION_RATE = int(os.environ.get('DEFAULT_LICENCE_DEPRECIATION_RATE', 50)) # noqa -CHECK_IP_HOSTNAME_ON_SAVE = bool_from_env('CHECK_IP_HOSTNAME_ON_SAVE', True) +DEFAULT_DEPRECIATION_RATE = int(os.environ.get("DEFAULT_DEPRECIATION_RATE", 25)) # noqa +DEFAULT_LICENCE_DEPRECIATION_RATE = int( + os.environ.get("DEFAULT_LICENCE_DEPRECIATION_RATE", 50) +) # noqa +CHECK_IP_HOSTNAME_ON_SAVE = bool_from_env("CHECK_IP_HOSTNAME_ON_SAVE", True) ASSET_HOSTNAME_TEMPLATE = { - 'prefix': '{{ country_code|upper }}{{ code|upper }}', - 'postfix': '', - 'counter_length': 5, + "prefix": "{{ country_code|upper }}{{ code|upper }}", + "postfix": "", + "counter_length": 5, } -DEFAULT_COUNTRY_CODE = os.environ.get('DEFAULT_COUNTRY_CODE', 'POL') +DEFAULT_COUNTRY_CODE = os.environ.get("DEFAULT_COUNTRY_CODE", "POL") -LDAP_SERVER_OBJECT_USER_CLASS = 'user' # possible values: user, person +LDAP_SERVER_OBJECT_USER_CLASS = "user" # possible values: user, person -ADMIN_SITE_HEADER = 'Ralph 3' -ADMIN_SITE_TITLE = 'Ralph 3' +ADMIN_SITE_HEADER = "Ralph 3" +ADMIN_SITE_TITLE = "Ralph 3" LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'verbose': { - 'datefmt': '%d.%m.%Y %H:%M:%S', - 'format': ( - '[%(asctime)08s,%(msecs)03d] %(levelname)-7s [%(processName)s' - ' %(process)d] %(module)s - %(message)s'), + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": { + "datefmt": "%d.%m.%Y %H:%M:%S", + "format": ( + "[%(asctime)08s,%(msecs)03d] %(levelname)-7s [%(processName)s" + " %(process)d] %(module)s - %(message)s" + ), }, - 'simple': { - 'datefmt': '%H:%M:%S', - 'format': '[%(asctime)08s] %(levelname)-7s %(message)s', + "simple": { + "datefmt": "%H:%M:%S", + "format": "[%(asctime)08s] %(levelname)-7s %(message)s", }, }, - 'handlers': { - 'console': { - 'level': 'DEBUG', - 'class': 'logging.StreamHandler', - 'formatter': 'simple', + "handlers": { + "console": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "simple", }, - 'file': { - 'level': 'INFO', - 'class': 'logging.handlers.RotatingFileHandler', - 'maxBytes': 1024 * 1024 * 100, # 100 MB - 'backupCount': 10, - 'filename': os.environ.get( - 'LOG_FILEPATH', LOG_FILEPATH - ), - 'formatter': 'verbose', + "file": { + "level": "INFO", + "class": "logging.handlers.RotatingFileHandler", + "maxBytes": 1024 * 1024 * 100, # 100 MB + "backupCount": 10, + "filename": os.environ.get("LOG_FILEPATH", LOG_FILEPATH), + "formatter": "verbose", }, }, - 'loggers': { - 'django.request': { - 'handlers': ['file'], - 'level': os.environ.get('LOGGING_DJANGO_REQUEST_LEVEL', 'WARNING'), - 'propagate': True, + "loggers": { + "django.request": { + "handlers": ["file"], + "level": os.environ.get("LOGGING_DJANGO_REQUEST_LEVEL", "WARNING"), + "propagate": True, }, - 'ralph': { - 'handlers': ['file'], - 'level': os.environ.get('LOGGING_RALPH_LEVEL', 'WARNING'), - 'propagate': True, + "ralph": { + "handlers": ["file"], + "level": os.environ.get("LOGGING_RALPH_LEVEL", "WARNING"), + "propagate": True, + }, + "rq.worker": { + "level": os.environ.get("LOGGING_RQ_LEVEL", "WARNING"), + "handlers": ["file"], + "propagate": True, }, - 'rq.worker': { - 'level': os.environ.get('LOGGING_RQ_LEVEL', 'WARNING'), - 'handlers': ['file'], - 'propagate': True, - } }, } REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework.authentication.TokenAuthentication', - 'rest_framework.authentication.BasicAuthentication', - 'rest_framework.authentication.SessionAuthentication', - ), - 'DEFAULT_PERMISSION_CLASSES': ( - 'ralph.lib.permissions.api.RalphPermission', + "DEFAULT_AUTHENTICATION_CLASSES": ( + "rest_framework.authentication.TokenAuthentication", + "rest_framework.authentication.BasicAuthentication", + "rest_framework.authentication.SessionAuthentication", ), - 'DEFAULT_FILTER_BACKENDS': ( - 'ralph.lib.permissions.api.PermissionsForObjectFilter', + "DEFAULT_PERMISSION_CLASSES": ("ralph.lib.permissions.api.RalphPermission",), + "DEFAULT_FILTER_BACKENDS": ( + "ralph.lib.permissions.api.PermissionsForObjectFilter", ), - 'DEFAULT_RENDERER_CLASSES': ( - 'rest_framework.renderers.JSONRenderer', - 'ralph.lib.api.utils.NoFiltersBrowsableAPIRenderer', - 'rest_framework_xml.renderers.XMLRenderer', + "DEFAULT_RENDERER_CLASSES": ( + "rest_framework.renderers.JSONRenderer", + "ralph.lib.api.utils.NoFiltersBrowsableAPIRenderer", + "rest_framework_xml.renderers.XMLRenderer", ), - 'DEFAULT_PARSER_CLASSES': ( - 'rest_framework.parsers.JSONParser', - 'rest_framework.parsers.FormParser', - 'rest_framework.parsers.MultiPartParser', - 'rest_framework_xml.parsers.XMLParser', + "DEFAULT_PARSER_CLASSES": ( + "rest_framework.parsers.JSONParser", + "rest_framework.parsers.FormParser", + "rest_framework.parsers.MultiPartParser", + "rest_framework_xml.parsers.XMLParser", ), - 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', # noqa - 'PAGE_SIZE': 10, - 'DEFAULT_METADATA_CLASS': 'ralph.lib.api.utils.RalphApiMetadata', - 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning', # noqa - 'DEFAULT_VERSION': 'v1', - 'ALLOWED_VERSIONS': ('v1',), - 'EXCEPTION_HANDLER': 'ralph.lib.api.exception_handler.validation_error_exception_handler', # noqa + "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination", # noqa + "PAGE_SIZE": 10, + "DEFAULT_METADATA_CLASS": "ralph.lib.api.utils.RalphApiMetadata", + "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.AcceptHeaderVersioning", # noqa + "DEFAULT_VERSION": "v1", + "ALLOWED_VERSIONS": ("v1",), + "EXCEPTION_HANDLER": "ralph.lib.api.exception_handler.validation_error_exception_handler", # noqa } -API_THROTTLING = bool_from_env('API_THROTTLING', default=False) +API_THROTTLING = bool_from_env("API_THROTTLING", default=False) if API_THROTTLING: - REST_FRAMEWORK.update({ - 'DEFAULT_THROTTLE_CLASSES': ( - 'rest_framework.throttling.UserRateThrottle', - ), - 'DEFAULT_THROTTLE_RATES': { - 'user': os.environ.get('API_THROTTLING_USER', '5000/hour') + REST_FRAMEWORK.update( + { + "DEFAULT_THROTTLE_CLASSES": ("rest_framework.throttling.UserRateThrottle",), + "DEFAULT_THROTTLE_RATES": { + "user": os.environ.get("API_THROTTLING_USER", "5000/hour") + }, } - }) + ) -REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD', 'ralph_ng') -REDIS_SENTINEL_ENABLED = bool_from_env('REDIS_SENTINEL_ENABLED', False) -REDIS_SOCKET_TIMEOUT = float(os.environ.get('REDIS_SOCKET_TIMEOUT', 1.0)) -REDIS_CONNECT_TIMEOUT = float(os.environ.get('REDIS_CONNECT_TIMEOUT', 1.0)) -REDIS_COMMAND_TIMEOUT = float(os.environ.get('REDIS_COMMAND_TIMEOUT', 10.0)) +REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD", "ralph_ng") +REDIS_SENTINEL_ENABLED = bool_from_env("REDIS_SENTINEL_ENABLED", False) +REDIS_SOCKET_TIMEOUT = float(os.environ.get("REDIS_SOCKET_TIMEOUT", 1.0)) +REDIS_CONNECT_TIMEOUT = float(os.environ.get("REDIS_CONNECT_TIMEOUT", 1.0)) +REDIS_COMMAND_TIMEOUT = float(os.environ.get("REDIS_COMMAND_TIMEOUT", 10.0)) if REDIS_SENTINEL_ENABLED: from redis.sentinel import Sentinel - REDIS_SENTINEL_HOSTS = get_sentinels(os.environ.get('REDIS_SENTINEL_HOSTS', None)) # noqa - REDIS_CLUSTER_NAME = os.environ.get('REDIS_CLUSTER_NAME', 'ralph_ng') - REDIS_SENTINEL_SOCKET_TIMEOUT = float(os.environ.get('REDIS_SENTINEL_SOCKET_TIMEOUT', 1.0)) # noqa + REDIS_SENTINEL_HOSTS = get_sentinels(os.environ.get("REDIS_SENTINEL_HOSTS", None)) # noqa + REDIS_CLUSTER_NAME = os.environ.get("REDIS_CLUSTER_NAME", "ralph_ng") + REDIS_SENTINEL_SOCKET_TIMEOUT = float( + os.environ.get("REDIS_SENTINEL_SOCKET_TIMEOUT", 1.0) + ) # noqa sentinel = Sentinel( REDIS_SENTINEL_HOSTS, socket_timeout=REDIS_SENTINEL_SOCKET_TIMEOUT, - password=REDIS_PASSWORD + password=REDIS_PASSWORD, ) REDIS_MASTER = sentinel.master_for(REDIS_CLUSTER_NAME) REDIS_CONNECTION = { - 'SENTINELS': REDIS_SENTINEL_HOSTS, - 'DB': int(os.environ.get('REDIS_DB', 0)), - 'PASSWORD': REDIS_PASSWORD, - 'TIMEOUT': REDIS_COMMAND_TIMEOUT, - 'CONNECT_TIMEOUT': REDIS_CONNECT_TIMEOUT, + "SENTINELS": REDIS_SENTINEL_HOSTS, + "DB": int(os.environ.get("REDIS_DB", 0)), + "PASSWORD": REDIS_PASSWORD, + "TIMEOUT": REDIS_COMMAND_TIMEOUT, + "CONNECT_TIMEOUT": REDIS_CONNECT_TIMEOUT, } RQ_QUEUES = { - 'default': { - 'SENTINELS': REDIS_SENTINEL_HOSTS, - 'MASTER_NAME': REDIS_CLUSTER_NAME, - 'DB': int(os.environ.get('REDIS_DB', 0)), - 'PASSWORD': REDIS_PASSWORD, - 'CONNECTION_KWARGS': { - 'socket_connect_timeout': REDIS_CONNECT_TIMEOUT, - 'retry_on_timeout': True + "default": { + "SENTINELS": REDIS_SENTINEL_HOSTS, + "MASTER_NAME": REDIS_CLUSTER_NAME, + "DB": int(os.environ.get("REDIS_DB", 0)), + "PASSWORD": REDIS_PASSWORD, + "CONNECTION_KWARGS": { + "socket_connect_timeout": REDIS_CONNECT_TIMEOUT, + "retry_on_timeout": True, }, }, } @@ -369,55 +373,51 @@ def get_sentinels(sentinels_string): REDIS_MASTER_IP = None REDIS_MASTER_PORT = None REDIS_CONNECTION = { - 'HOST': REDIS_MASTER_IP or os.environ.get('REDIS_HOST', 'localhost'), # noqa - 'PORT': REDIS_MASTER_PORT or os.environ.get('REDIS_PORT', '6379'), - 'DB': int(os.environ.get('REDIS_DB', 0)), - 'PASSWORD': os.environ.get('REDIS_PASSWORD', ''), - 'TIMEOUT': REDIS_COMMAND_TIMEOUT, - 'CONNECT_TIMEOUT': REDIS_CONNECT_TIMEOUT, - } - RQ_QUEUES = { - 'default': dict( - **REDIS_CONNECTION - ) + "HOST": REDIS_MASTER_IP or os.environ.get("REDIS_HOST", "localhost"), # noqa + "PORT": REDIS_MASTER_PORT or os.environ.get("REDIS_PORT", "6379"), + "DB": int(os.environ.get("REDIS_DB", 0)), + "PASSWORD": os.environ.get("REDIS_PASSWORD", ""), + "TIMEOUT": REDIS_COMMAND_TIMEOUT, + "CONNECT_TIMEOUT": REDIS_CONNECT_TIMEOUT, } + RQ_QUEUES = {"default": dict(**REDIS_CONNECTION)} # set to False to turn off cache decorator -USE_CACHE = bool_from_env('USE_CACHE', True) +USE_CACHE = bool_from_env("USE_CACHE", True) -SENTRY_ENABLED = bool_from_env('SENTRY_ENABLED') +SENTRY_ENABLED = bool_from_env("SENTRY_ENABLED") BACK_OFFICE_ASSET_AUTO_ASSIGN_HOSTNAME = bool_from_env( - 'BACK_OFFICE_ASSET_AUTO_ASSIGN_HOSTNAME', False + "BACK_OFFICE_ASSET_AUTO_ASSIGN_HOSTNAME", False ) BACKOFFICE_HOSTNAME_FIELD_READONLY = bool_from_env( - 'BACKOFFICE_HOSTNAME_FIELD_READONLY', False + "BACKOFFICE_HOSTNAME_FIELD_READONLY", False ) TAGGIT_CASE_INSENSITIVE = True # case insensitive tags RALPH_QUEUES = { - 'ralph_ext_pdf': {}, - 'ralph_async_transitions': { - 'DEFAULT_TIMEOUT': 3600, + "ralph_ext_pdf": {}, + "ralph_async_transitions": { + "DEFAULT_TIMEOUT": 3600, }, } for queue_name, options in RALPH_QUEUES.items(): - RQ_QUEUES[queue_name] = ChainMap(RQ_QUEUES['default'], options) + RQ_QUEUES[queue_name] = ChainMap(RQ_QUEUES["default"], options) RALPH_EXTERNAL_SERVICES = { - 'PDF': { - 'queue_name': 'ralph_ext_pdf', - 'method': 'inkpy_jinja.pdf', + "PDF": { + "queue_name": "ralph_ext_pdf", + "method": "inkpy_jinja.pdf", }, } RALPH_INTERNAL_SERVICES = { - 'ASYNC_TRANSITIONS': { - 'queue_name': 'ralph_async_transitions', - 'method': 'ralph.lib.transitions.async.run_async_transition' + "ASYNC_TRANSITIONS": { + "queue_name": "ralph_async_transitions", + "method": "ralph.lib.transitions.async.run_async_transition", } } @@ -439,146 +439,142 @@ def get_sentinels(sentinels_string): # MY_EQUIPMENT_LINKS = [ # {'url': 'http://....', 'name': 'Link name'}, # ] -MY_EQUIPMENT_LINKS = json.loads(os.environ.get('MY_EQUIPMENT_LINKS', '[]')) -MANAGING_DEVICES_MOVED_INFO = os.environ.get('MANAGING_DEVICES_MOVED_INFO', '') # noqa -MY_EQUIPMENT_REPORT_FAILURE_URL = os.environ.get('MY_EQUIPMENT_REPORT_FAILURE_URL', '') # noqa -MY_EQUIPMENT_SHOW_BUYOUT_DATE = bool_from_env('MY_EQUIPMENT_SHOW_BUYOUT_DATE') -MY_EQUIPMENT_BUYOUT_URL = os.environ.get('MY_EQUIPMENT_BUYOUT_URL', '') +MY_EQUIPMENT_LINKS = json.loads(os.environ.get("MY_EQUIPMENT_LINKS", "[]")) +MANAGING_DEVICES_MOVED_INFO = os.environ.get("MANAGING_DEVICES_MOVED_INFO", "") # noqa +MY_EQUIPMENT_REPORT_FAILURE_URL = os.environ.get("MY_EQUIPMENT_REPORT_FAILURE_URL", "") # noqa +MY_EQUIPMENT_SHOW_BUYOUT_DATE = bool_from_env("MY_EQUIPMENT_SHOW_BUYOUT_DATE") +MY_EQUIPMENT_BUYOUT_URL = os.environ.get("MY_EQUIPMENT_BUYOUT_URL", "") # Sets URL shown to user if they declare that they dp not have specific asset. -MISSING_ASSET_REPORT_URL = os.environ.get('MISSING_ASSET_REPORT_URL', None) +MISSING_ASSET_REPORT_URL = os.environ.get("MISSING_ASSET_REPORT_URL", None) # Redirect to result detail view if there is only one in search result list REDIRECT_TO_DETAIL_VIEW_IF_ONE_SEARCH_RESULT = bool_from_env( - 'REDIRECT_TO_DETAIL_VIEW_IF_ONE_SEARCH_RESULT', True + "REDIRECT_TO_DETAIL_VIEW_IF_ONE_SEARCH_RESULT", True ) # Stocktaking tagging config - each variable describes individual tag. # To disable tag set it to None or, in case of date tag, set variable to '0'. -INVENTORY_TAG = os.environ.get('INVENTORY_TAG', 'INV') +INVENTORY_TAG = os.environ.get("INVENTORY_TAG", "INV") # This tag means user himself confirmed asset possession. -INVENTORY_TAG_USER = os.environ.get('INVENTORY_TAG_USER', 'INV_CONF') -INVENTORY_TAG_MISSING = os.environ.get('INVENTORY_TAG_MISSING', 'INV_MISSING') -INVENTORY_TAG_APPEND_DATE = bool_from_env('INVENTORY_TAG_APPEND_DATE', True) +INVENTORY_TAG_USER = os.environ.get("INVENTORY_TAG_USER", "INV_CONF") +INVENTORY_TAG_MISSING = os.environ.get("INVENTORY_TAG_MISSING", "INV_MISSING") +INVENTORY_TAG_APPEND_DATE = bool_from_env("INVENTORY_TAG_APPEND_DATE", True) -ENABLE_ACCEPT_ASSETS_FOR_CURRENT_USER = bool_from_env('ENABLE_ACCEPT_ASSETS_FOR_CURRENT_USER') # noqa +ENABLE_ACCEPT_ASSETS_FOR_CURRENT_USER = bool_from_env( + "ENABLE_ACCEPT_ASSETS_FOR_CURRENT_USER" +) # noqa ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG = { - 'TRANSITION_ID': os.environ.get( - 'ACCEPT_ASSETS_FOR_CURRENT_USER_TRANSITION_ID', None - ), - 'TRANSITION_SIM_ID': os.environ.get( - 'ACCEPT_SIMCARD_FOR_CURRENT_USER_CONFIG', None + "TRANSITION_ID": os.environ.get( + "ACCEPT_ASSETS_FOR_CURRENT_USER_TRANSITION_ID", None ), - 'TRANSITION_ACCESS_CARD_ID': os.environ.get( - 'ACCEPT_ACCESS_CARD_FOR_CURRENT_USER_CONFIG', None + "TRANSITION_SIM_ID": os.environ.get("ACCEPT_SIMCARD_FOR_CURRENT_USER_CONFIG", None), + "TRANSITION_ACCESS_CARD_ID": os.environ.get( + "ACCEPT_ACCESS_CARD_FOR_CURRENT_USER_CONFIG", None ), # in_progress by default - 'BACK_OFFICE_ACCEPT_STATUS': os.environ.get( - 'ACCEPT_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS', 2 + "BACK_OFFICE_ACCEPT_STATUS": os.environ.get( + "ACCEPT_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS", 2 ), - 'SIMCARD_ACCEPT_STATUS': os.environ.get( - 'SIMCARD_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS', 2 + "SIMCARD_ACCEPT_STATUS": os.environ.get( + "SIMCARD_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS", 2 ), - 'ACCESS_CARD_ACCEPT_ACCEPT_STATUS': os.environ.get( - 'ACCESS_CARD_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS', 2 + "ACCESS_CARD_ACCEPT_ACCEPT_STATUS": os.environ.get( + "ACCESS_CARD_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS", 2 ), - 'LOAN_TRANSITION_ID': os.environ.get( - 'LOAN_ASSETS_FOR_CURRENT_USER_TRANSITION_ID', None + "LOAN_TRANSITION_ID": os.environ.get( + "LOAN_ASSETS_FOR_CURRENT_USER_TRANSITION_ID", None ), # loan_in_progress by default - 'BACK_OFFICE_ACCEPT_LOAN_STATUS': os.environ.get( - 'LOAN_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS', 13 + "BACK_OFFICE_ACCEPT_LOAN_STATUS": os.environ.get( + "LOAN_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS", 13 ), - 'RETURN_TRANSITION_ID': os.environ.get( - 'RETURN_ASSETS_FOR_CURRENT_USER_TRANSITION_ID', None + "RETURN_TRANSITION_ID": os.environ.get( + "RETURN_ASSETS_FOR_CURRENT_USER_TRANSITION_ID", None ), # waiting_for_return by default - 'BACK_OFFICE_ACCEPT_RETURN_STATUS': os.environ.get( - 'RETURN_ASSESTS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS', 14 + "BACK_OFFICE_ACCEPT_RETURN_STATUS": os.environ.get( + "RETURN_ASSESTS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS", 14 ), - 'BACK_OFFICE_TEAM_ACCEPT_STATUS': os.environ.get( - 'ACCEPT_TEAM_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS', 20 + "BACK_OFFICE_TEAM_ACCEPT_STATUS": os.environ.get( + "ACCEPT_TEAM_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS", 20 ), - 'TRANSITION_TEAM_ACCEPT_ID': os.environ.get( - 'ACCEPT_TEAM_ASSETS_FOR_CURRENT_USER_TRANSITION_ID', None + "TRANSITION_TEAM_ACCEPT_ID": os.environ.get( + "ACCEPT_TEAM_ASSETS_FOR_CURRENT_USER_TRANSITION_ID", None ), - 'BACK_OFFICE_TEST_ACCEPT_STATUS': os.environ.get( - 'ACCEPT_TEST_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS', 21 + "BACK_OFFICE_TEST_ACCEPT_STATUS": os.environ.get( + "ACCEPT_TEST_ASSETS_FOR_CURRENT_USER_BACK_OFFICE_ACCEPT_STATUS", 21 ), - 'TRANSITION_TEST_ACCEPT_ID': os.environ.get( - 'ACCEPT_TEST_ASSETS_FOR_CURRENT_USER_TRANSITION_ID', None + "TRANSITION_TEST_ACCEPT_ID": os.environ.get( + "ACCEPT_TEST_ASSETS_FOR_CURRENT_USER_TRANSITION_ID", None ), } RELEASE_REPORT_CONFIG = { # report with name 'release' is by default - 'DEFAULT_REPORT': os.environ.get( - 'RELEASE_REPORT_CONFIG_DEFAULT_REPORT', 'release' - ), + "DEFAULT_REPORT": os.environ.get("RELEASE_REPORT_CONFIG_DEFAULT_REPORT", "release"), # map transition id to different report - 'REPORTS_MAPPER': json.loads( - os.environ.get('RELEASE_REPORT_CONFIG_REPORTS_MAPPER', '{}') - ) + "REPORTS_MAPPER": json.loads( + os.environ.get("RELEASE_REPORT_CONFIG_REPORTS_MAPPER", "{}") + ), } MAP_IMPORTED_ID_TO_NEW_ID = False -OPENSTACK_INSTANCES = json.loads(os.environ.get('OPENSTACK_INSTANCES', '[]')) +OPENSTACK_INSTANCES = json.loads(os.environ.get("OPENSTACK_INSTANCES", "[]")) DEFAULT_OPENSTACK_PROVIDER_NAME = os.environ.get( - 'DEFAULT_OPENSTACK_PROVIDER_NAME', 'openstack' + "DEFAULT_OPENSTACK_PROVIDER_NAME", "openstack" ) # issue tracker url for Operations urls (issues ids) - should end with / -ISSUE_TRACKER_URL = os.environ.get('ISSUE_TRACKER_URL', '') +ISSUE_TRACKER_URL = os.environ.get("ISSUE_TRACKER_URL", "") # Networks -DEFAULT_NETWORK_BOTTOM_MARGIN = int(os.environ.get('DEFAULT_NETWORK_BOTTOM_MARGIN', 10)) # noqa -DEFAULT_NETWORK_TOP_MARGIN = int(os.environ.get('DEFAULT_NETWORK_TOP_MARGIN', 0)) # noqa +DEFAULT_NETWORK_BOTTOM_MARGIN = int(os.environ.get("DEFAULT_NETWORK_BOTTOM_MARGIN", 10)) # noqa +DEFAULT_NETWORK_TOP_MARGIN = int(os.environ.get("DEFAULT_NETWORK_TOP_MARGIN", 0)) # noqa # deprecated, to remove in the future -DEFAULT_NETWORK_MARGIN = int(os.environ.get('DEFAULT_NETWORK_MARGIN', 10)) +DEFAULT_NETWORK_MARGIN = int(os.environ.get("DEFAULT_NETWORK_MARGIN", 10)) # when set to True, network records (IP/Ethernet) can't be modified until # 'expose in DHCP' is selected -DHCP_ENTRY_FORBID_CHANGE = bool_from_env('DHCP_ENTRY_FORBID_CHANGE', True) +DHCP_ENTRY_FORBID_CHANGE = bool_from_env("DHCP_ENTRY_FORBID_CHANGE", True) # disable integration with DNSaaS as it's no longer supported # https://github.com/allegro/django-powerdns-dnssec # This settings will be deleted in future release. ENABLE_DNSAAS_INTEGRATION = False -DNSAAS_URL = os.environ.get('DNSAAS_URL', '') -DNSAAS_TOKEN = os.environ.get('DNSAAS_TOKEN', '') -DNSAAS_TIMEOUT = os.environ.get('DNSAAS_TIMEOUT', 10) -DNSAAS_AUTO_PTR_ALWAYS = os.environ.get('DNSAAS_AUTO_PTR_ALWAYS', 2) -DNSAAS_AUTO_PTR_NEVER = os.environ.get('DNSAAS_AUTO_PTR_NEVER', 1) +DNSAAS_URL = os.environ.get("DNSAAS_URL", "") +DNSAAS_TOKEN = os.environ.get("DNSAAS_TOKEN", "") +DNSAAS_TIMEOUT = os.environ.get("DNSAAS_TIMEOUT", 10) +DNSAAS_AUTO_PTR_ALWAYS = os.environ.get("DNSAAS_AUTO_PTR_ALWAYS", 2) +DNSAAS_AUTO_PTR_NEVER = os.environ.get("DNSAAS_AUTO_PTR_NEVER", 1) # user in dnsaas which can do changes, like update TXT records etc. -DNSAAS_OWNER = os.environ.get('DNSAAS_OWNER', 'ralph') +DNSAAS_OWNER = os.environ.get("DNSAAS_OWNER", "ralph") # pyhermes topic where messages about auto txt records are announced DNSAAS_AUTO_TXT_RECORD_TOPIC_NAME = None # define names of values send to DNSAAS for: # DataCenterAsset, Cluster, VirtualServer DNSAAS_AUTO_TXT_RECORD_PURPOSE_MAP = { # self.configuration_path.class will be send as 'VENTURE' - 'class_name': 'VENTURE', + "class_name": "VENTURE", # self.configuration_path.module will be send as 'ROLE' - 'module_name': 'ROLE', + "module_name": "ROLE", # self.configuration_path.path will be send as 'PATH' - 'configuration_path': 'CONFIGURATION_PATH', + "configuration_path": "CONFIGURATION_PATH", # self.service_env will be send as 'SERVICE_ENV' - 'service_env': 'SERVICE_ENV', + "service_env": "SERVICE_ENV", # self.model will be send as 'MODEL' - 'model': 'MODEL', + "model": "MODEL", # self.location will be send as 'LOCATION' - 'location': 'LOCATION', + "location": "LOCATION", # self.location will be send as 'LOCATION' # if any of above is set to none # 'location': None # then this value won't be set at all } -DNSAAS_AUTO_UPDATE_HOST_DNS = bool_from_env('DNSAAS_AUTO_UPDATE_HOST_DNS') +DNSAAS_AUTO_UPDATE_HOST_DNS = bool_from_env("DNSAAS_AUTO_UPDATE_HOST_DNS") -DOMAIN_DATA_UPDATE_TOPIC = os.environ.get( - 'DOMAIN_DATA_UPDATE_TOPIC', None -) +DOMAIN_DATA_UPDATE_TOPIC = os.environ.get("DOMAIN_DATA_UPDATE_TOPIC", None) DOMAIN_OWNER_TYPE = { - 'BO': 'Business Owner', - 'TO': 'Technical Owner', + "BO": "Business Owner", + "TO": "Technical Owner", } # Transitions settings @@ -590,99 +586,77 @@ def get_sentinels(sentinels_string): # Change management settings CHANGE_MGMT_OPERATION_STATUSES = { - 'OPENED': os.getenv( - 'CHANGE_MGMT_OPERATION_STATUS_OPENED', 'Open' - ), - 'IN_PROGRESS': os.getenv( - 'CHANGE_MGMT_OPERATION_STATUS_IN_PROGRESS', 'In Progress' - ), - 'RESOLVED': os.getenv( - 'CHANGE_MGMT_OPERATION_STATUS_RESOLVED', 'Resolved' - ), - 'CLOSED': os.getenv( - 'CHANGE_MGMT_OPERATION_STATUS_CLOSED', 'Closed' - ), - 'REOPENED': os.getenv( - 'CHANGE_MGMT_OPERATION_STATUS_REOPENED', 'Reopened' - ), - 'TODO': os.getenv( - 'CHANGE_MGMT_OPERATION_STATUS_TODO', 'Todo' - ), - 'BLOCKED': os.getenv( - 'CHANGE_MGMT_OPERATION_STATUS_BLOCKED', 'Blocked' - ) + "OPENED": os.getenv("CHANGE_MGMT_OPERATION_STATUS_OPENED", "Open"), + "IN_PROGRESS": os.getenv("CHANGE_MGMT_OPERATION_STATUS_IN_PROGRESS", "In Progress"), + "RESOLVED": os.getenv("CHANGE_MGMT_OPERATION_STATUS_RESOLVED", "Resolved"), + "CLOSED": os.getenv("CHANGE_MGMT_OPERATION_STATUS_CLOSED", "Closed"), + "REOPENED": os.getenv("CHANGE_MGMT_OPERATION_STATUS_REOPENED", "Reopened"), + "TODO": os.getenv("CHANGE_MGMT_OPERATION_STATUS_TODO", "Todo"), + "BLOCKED": os.getenv("CHANGE_MGMT_OPERATION_STATUS_BLOCKED", "Blocked"), } -CHANGE_MGMT_BASE_OBJECT_LOADER = os.getenv( - 'CHANGE_MGMT_BASE_OBJECT_LOADER', None -) +CHANGE_MGMT_BASE_OBJECT_LOADER = os.getenv("CHANGE_MGMT_BASE_OBJECT_LOADER", None) CHANGE_MGMT_PROCESSOR = os.getenv( - 'CHANGE_MGMT_PROCESSOR', 'ralph.operations.changemanagement.jira' + "CHANGE_MGMT_PROCESSOR", "ralph.operations.changemanagement.jira" ) HERMES_CHANGE_MGMT_TOPICS = { - 'CHANGES': os.getenv( - 'HERMES_CHANGE_MGMT_CHANGES_TOPIC', 'hermes.changemanagement.changes' + "CHANGES": os.getenv( + "HERMES_CHANGE_MGMT_CHANGES_TOPIC", "hermes.changemanagement.changes" ) } # Hermes settings -ENABLE_HERMES_INTEGRATION = bool_from_env('ENABLE_HERMES_INTEGRATION') -HERMES = json.loads(os.environ.get('HERMES', '{}')) -HERMES['ENABLED'] = ENABLE_HERMES_INTEGRATION +ENABLE_HERMES_INTEGRATION = bool_from_env("ENABLE_HERMES_INTEGRATION") +HERMES = json.loads(os.environ.get("HERMES", "{}")) +HERMES["ENABLED"] = ENABLE_HERMES_INTEGRATION # topic name where DC asset, cloud host, virtual server changes should be # announced -HERMES_HOST_UPDATE_TOPIC_NAME = os.environ.get( - 'HERMES_HOST_UPDATE_TOPIC_NAME', None -) +HERMES_HOST_UPDATE_TOPIC_NAME = os.environ.get("HERMES_HOST_UPDATE_TOPIC_NAME", None) HERMES_SERVICE_TOPICS = { - 'CREATE': os.environ.get( - 'SERVICE_CREATE_HERMES_TOPIC_NAME', 'hermes.service.create' + "CREATE": os.environ.get( + "SERVICE_CREATE_HERMES_TOPIC_NAME", "hermes.service.create" ), - 'DELETE': os.environ.get( - 'SERVICE_DELETE_HERMES_TOPIC_NAME', 'hermes.service.delete' + "DELETE": os.environ.get( + "SERVICE_DELETE_HERMES_TOPIC_NAME", "hermes.service.delete" ), - 'UPDATE': os.environ.get( - 'SERVICE_UPDATE_HERMES_TOPIC_NAME', 'hermes.service.update' + "UPDATE": os.environ.get( + "SERVICE_UPDATE_HERMES_TOPIC_NAME", "hermes.service.update" + ), + "REFRESH": os.environ.get( + "SERVICE_REFRESH_HERMES_TOPIC_NAME", "hermes.service.refresh" ), - 'REFRESH': os.environ.get( - 'SERVICE_REFRESH_HERMES_TOPIC_NAME', 'hermes.service.refresh' - ) } if ENABLE_HERMES_INTEGRATION: - INSTALLED_APPS += ( - 'pyhermes.apps.django', - ) + INSTALLED_APPS += ("pyhermes.apps.django",) ENABLE_SAVE_DESCENDANTS_DURING_NETWORK_SYNC = bool_from_env( - 'ENABLE_SAVE_DESCENDANTS_DURING_NETWORK_SYNC', True -) -ENABLE_EMAIL_NOTIFICATION = bool_from_env('ENABLE_EMAIL_NOTIFICATION') - -EMAIL_HOST = os.environ.get('EMAIL_HOST', None) -EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', None) -EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER', None) -EMAIL_PORT = os.environ.get('EMAIL_PORT', 25) -EMAIL_USE_TLS = bool_from_env('EMAIL_USE_TLS', False) - -EMAIL_FROM = os.environ.get('EMAIL_FROM', None) -EMAIL_MESSAGE_CONTACT_NAME = os.environ.get('EMAIL_MESSAGE_CONTACT_NAME', None) -EMAIL_MESSAGE_CONTACT_EMAIL = os.environ.get( - 'EMAIL_MESSAGE_CONTACT_EMAIL', None + "ENABLE_SAVE_DESCENDANTS_DURING_NETWORK_SYNC", True ) +ENABLE_EMAIL_NOTIFICATION = bool_from_env("ENABLE_EMAIL_NOTIFICATION") + +EMAIL_HOST = os.environ.get("EMAIL_HOST", None) +EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", None) +EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", None) +EMAIL_PORT = os.environ.get("EMAIL_PORT", 25) +EMAIL_USE_TLS = bool_from_env("EMAIL_USE_TLS", False) + +EMAIL_FROM = os.environ.get("EMAIL_FROM", None) +EMAIL_MESSAGE_CONTACT_NAME = os.environ.get("EMAIL_MESSAGE_CONTACT_NAME", None) +EMAIL_MESSAGE_CONTACT_EMAIL = os.environ.get("EMAIL_MESSAGE_CONTACT_EMAIL", None) -SCM_TOOL_URL = os.getenv('SCM_TOOL_URL', '') +SCM_TOOL_URL = os.getenv("SCM_TOOL_URL", "") -RALPH_HOST_URL = os.environ.get('RALPH_HOST_URL', None) +RALPH_HOST_URL = os.environ.get("RALPH_HOST_URL", None) # METRICS COLLECT_METRICS = False ALLOW_PUSH_GRAPHS_DATA_TO_STATSD = False -STATSD_GRAPHS_PREFIX = 'ralph.graphs' +STATSD_GRAPHS_PREFIX = "ralph.graphs" ENABLE_REQUESTS_AND_QUERIES_METRICS = True LARGE_NUMBER_OF_QUERIES_THRESHOLD = 25 @@ -694,21 +668,20 @@ def get_sentinels(sentinels_string): CONVERT_TO_BACKOFFICE_ASSET_DEFAULT_STATUS_ID = 1 # Currency choices for django-money -DEFAULT_CURRENCY_CODE = 'XXX' +DEFAULT_CURRENCY_CODE = "XXX" CURRENCY_CHOICES = [ - (c.code, c.code) for i, c in CURRENCIES.items() - if c.code != DEFAULT_CURRENCY_CODE + (c.code, c.code) for i, c in CURRENCIES.items() if c.code != DEFAULT_CURRENCY_CODE ] -CURRENCY_CHOICES.append(('XXX', '---')) +CURRENCY_CHOICES.append(("XXX", "---")) OAUTH_CLIENT_ID = "" OAUTH_SECRET = "" OAUTH_TOKEN_URL = "https://localhost/" -GOOGLE_TAG_MANAGER_TAG_ID = os.environ.get('GOOGLE_TAG_MANAGER_TAG_ID', None) +GOOGLE_TAG_MANAGER_TAG_ID = os.environ.get("GOOGLE_TAG_MANAGER_TAG_ID", None) -ASSET_BUYOUT_CATEGORY_TO_MONTHS = json.loads(os.environ.get( - 'ASSET_BUYOUT_CATEGORY_TO_MONTHS', '{}') +ASSET_BUYOUT_CATEGORY_TO_MONTHS = json.loads( + os.environ.get("ASSET_BUYOUT_CATEGORY_TO_MONTHS", "{}") ) DATA_UPLOAD_MAX_NUMBER_FIELDS = 3000 diff --git a/src/ralph/settings/dev.py b/src/ralph/settings/dev.py index 5a768d93cb..35cf9c1c7e 100644 --- a/src/ralph/settings/dev.py +++ b/src/ralph/settings/dev.py @@ -2,63 +2,57 @@ def only_true(request): - '''For django debug toolbar.''' + """For django debug toolbar.""" return True DEBUG = True INSTALLED_APPS = INSTALLED_APPS + ( - 'debug_toolbar', - 'django_extensions', + "debug_toolbar", + "django_extensions", ) -MIDDLEWARE = MIDDLEWARE + ( - 'debug_toolbar.middleware.DebugToolbarMiddleware', -) +MIDDLEWARE = MIDDLEWARE + ("debug_toolbar.middleware.DebugToolbarMiddleware",) DEBUG_TOOLBAR_CONFIG = { - 'SHOW_TOOLBAR_CALLBACK': "%s.only_true" % __name__, + "SHOW_TOOLBAR_CALLBACK": "%s.only_true" % __name__, } -ROOT_URLCONF = 'ralph.urls.dev' +ROOT_URLCONF = "ralph.urls.dev" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], - 'loaders': [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - 'ralph.lib.template.loaders.AppTemplateLoader', + "loaders": [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + "ralph.lib.template.loaders.AppTemplateLoader", ], }, }, ] -LOGGING['handlers']['console']['level'] = 'DEBUG' -for logger in LOGGING['loggers']: - LOGGING['loggers'][logger]['level'] = 'DEBUG' - LOGGING['loggers'][logger]['handlers'].append('console') +LOGGING["handlers"]["console"]["level"] = "DEBUG" +for logger in LOGGING["loggers"]: + LOGGING["loggers"][logger]["level"] = "DEBUG" + LOGGING["loggers"][logger]["handlers"].append("console") -if bool_from_env('RALPH_PROFILING'): +if bool_from_env("RALPH_PROFILING"): SILKY_PYTHON_PROFILER = True - MIDDLEWARE = MIDDLEWARE + ( - 'silk.middleware.SilkyMiddleware', - ) - INSTALLED_APPS = INSTALLED_APPS + ( - 'silk', - ) + MIDDLEWARE = MIDDLEWARE + ("silk.middleware.SilkyMiddleware",) + INSTALLED_APPS = INSTALLED_APPS + ("silk",) SILKY_DYNAMIC_PROFILING = [ { - 'module': 'ralph.data_center.admin', - 'function': 'DataCenterAssetAdmin.changelist_view' + "module": "ralph.data_center.admin", + "function": "DataCenterAssetAdmin.changelist_view", }, ] -ADMIN_SITE_HEADER = 'Ralph DEV' -ADMIN_SITE_TITLE = 'Ralph DEV' +ADMIN_SITE_HEADER = "Ralph DEV" +ADMIN_SITE_TITLE = "Ralph DEV" diff --git a/src/ralph/settings/hooks.py b/src/ralph/settings/hooks.py index 06535bb984..1c900c0472 100644 --- a/src/ralph/settings/hooks.py +++ b/src/ralph/settings/hooks.py @@ -3,8 +3,7 @@ from ralph.lib.hooks import hook_name_to_env_name -HOOKS = ('back_office.transition_action.email_context',) +HOOKS = ("back_office.transition_action.email_context",) HOOKS_CONFIGURATION = { - hook: os.environ.get(hook_name_to_env_name(hook), 'default') - for hook in HOOKS + hook: os.environ.get(hook_name_to_env_name(hook), "default") for hook in HOOKS } diff --git a/src/ralph/settings/prod.py b/src/ralph/settings/prod.py index 33a590ba34..d1d02bed15 100644 --- a/src/ralph/settings/prod.py +++ b/src/ralph/settings/prod.py @@ -3,86 +3,79 @@ from ralph.settings import * # noqa -DEBUG = bool_from_env('RALPH_DEBUG', False) +DEBUG = bool_from_env("RALPH_DEBUG", False) -STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' # noqa +STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" # noqa -REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = ( - 'rest_framework.authentication.TokenAuthentication', +REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = ( + "rest_framework.authentication.TokenAuthentication", # session authentication enabled for API requests from UI (ex. in # visualisation) - 'rest_framework.authentication.SessionAuthentication', + "rest_framework.authentication.SessionAuthentication", ) -if os.environ.get('STORE_SESSIONS_IN_REDIS'): - SESSION_ENGINE = 'redis_sessions.session' +if os.environ.get("STORE_SESSIONS_IN_REDIS"): + SESSION_ENGINE = "redis_sessions.session" if REDIS_SENTINEL_ENABLED: SESSION_REDIS_SENTINEL_LIST = REDIS_SENTINEL_HOSTS SESSION_REDIS_SENTINEL_MASTER_ALIAS = REDIS_CLUSTER_NAME else: - SESSION_REDIS_HOST = REDIS_CONNECTION['HOST'] - SESSION_REDIS_PORT = REDIS_CONNECTION['PORT'] - SESSION_REDIS_DB = REDIS_CONNECTION['DB'] - SESSION_REDIS_PASSWORD = REDIS_CONNECTION['PASSWORD'] - SESSION_REDIS_PREFIX = 'session' - -if os.environ.get('USE_REDIS_CACHE'): + SESSION_REDIS_HOST = REDIS_CONNECTION["HOST"] + SESSION_REDIS_PORT = REDIS_CONNECTION["PORT"] + SESSION_REDIS_DB = REDIS_CONNECTION["DB"] + SESSION_REDIS_PASSWORD = REDIS_CONNECTION["PASSWORD"] + SESSION_REDIS_PREFIX = "session" +if os.environ.get("USE_REDIS_CACHE"): DEFAULT_CACHE_OPTIONS = { - 'DB': os.environ.get('REDIS_CACHE_DB', REDIS_CONNECTION['DB']), - 'PASSWORD': os.environ.get( - 'REDIS_CACHE_PASSWORD', REDIS_CONNECTION['PASSWORD'] + "DB": os.environ.get("REDIS_CACHE_DB", REDIS_CONNECTION["DB"]), + "PASSWORD": os.environ.get( + "REDIS_CACHE_PASSWORD", REDIS_CONNECTION["PASSWORD"] ), - 'PARSER_CLASS': os.environ.get( - 'REDIS_CACHE_PARSER', 'redis.connection.HiredisParser' + "PARSER_CLASS": os.environ.get( + "REDIS_CACHE_PARSER", "redis.connection.HiredisParser" ), - 'CONNECTION_POOL_CLASS': os.environ.get( - 'REDIS_CACHE_CONNECTION_POOL_CLASS', - 'redis.BlockingConnectionPool' + "CONNECTION_POOL_CLASS": os.environ.get( + "REDIS_CACHE_CONNECTION_POOL_CLASS", "redis.BlockingConnectionPool" ), - 'PICKLE_VERSION': -1, + "PICKLE_VERSION": -1, } CACHES = { - 'default': { - 'OPTIONS': ( - json.loads(os.environ.get('REDIS_CACHE_OPTIONS', "{}")) or - DEFAULT_CACHE_OPTIONS + "default": { + "OPTIONS": ( + json.loads(os.environ.get("REDIS_CACHE_OPTIONS", "{}")) + or DEFAULT_CACHE_OPTIONS ), }, } if REDIS_SENTINEL_ENABLED: - CACHES['default']['BACKEND'] = 'ralph.lib.cache.DjangoConnectionPoolCache' # noqa + CACHES["default"]["BACKEND"] = "ralph.lib.cache.DjangoConnectionPoolCache" # noqa else: - CACHES['default']['BACKEND'] = 'redis_cache.RedisCache' - CACHES['default']['LOCATION'] = json.loads( + CACHES["default"]["BACKEND"] = "redis_cache.RedisCache" + CACHES["default"]["LOCATION"] = json.loads( os.environ.get( - 'REDIS_CACHE_LOCATION', '"{}:{}"'.format( - REDIS_CONNECTION['HOST'], REDIS_CONNECTION['PORT'] - ) + "REDIS_CACHE_LOCATION", + '"{}:{}"'.format(REDIS_CONNECTION["HOST"], REDIS_CONNECTION["PORT"]), ) ) - if bool_from_env('RALPH_DISABLE_CACHE_FRAGMENTS', False): - CACHES['template_fragments'] = { - 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + if bool_from_env("RALPH_DISABLE_CACHE_FRAGMENTS", False): + CACHES["template_fragments"] = { + "BACKEND": "django.core.cache.backends.dummy.DummyCache", } -if bool_from_env('COLLECT_METRICS'): +if bool_from_env("COLLECT_METRICS"): COLLECT_METRICS = True - STATSD_HOST = os.environ.get('STATSD_HOST') - STATSD_PORT = os.environ.get('STATSD_PORT') - STATSD_PREFIX = os.environ.get('STATSD_PREFIX') - STATSD_MAXUDPSIZE = int(os.environ.get('STATSD_MAXUDPSIZE', 512)) + STATSD_HOST = os.environ.get("STATSD_HOST") + STATSD_PORT = os.environ.get("STATSD_PORT") + STATSD_PREFIX = os.environ.get("STATSD_PREFIX") + STATSD_MAXUDPSIZE = int(os.environ.get("STATSD_MAXUDPSIZE", 512)) MIDDLEWARE = ( - 'ralph.lib.metrics.middlewares.RequestMetricsMiddleware', + "ralph.lib.metrics.middlewares.RequestMetricsMiddleware", ) + MIDDLEWARE - ALLOW_PUSH_GRAPHS_DATA_TO_STATSD = bool_from_env( - 'ALLOW_PUSH_GRAPHS_DATA_TO_STATSD' - ) + ALLOW_PUSH_GRAPHS_DATA_TO_STATSD = bool_from_env("ALLOW_PUSH_GRAPHS_DATA_TO_STATSD") if ALLOW_PUSH_GRAPHS_DATA_TO_STATSD: - STATSD_GRAPHS_PREFIX = os.environ.get( - 'STATSD_GRAPHS_PREFIX', 'ralph.graphs' - ) + STATSD_GRAPHS_PREFIX = os.environ.get("STATSD_GRAPHS_PREFIX", "ralph.graphs") diff --git a/src/ralph/settings/test.py b/src/ralph/settings/test.py index 72aa5910ca..3c9c06eb06 100644 --- a/src/ralph/settings/test.py +++ b/src/ralph/settings/test.py @@ -3,40 +3,44 @@ from ralph.settings import * # noqa # for dhcp agent test -sys.path.append(os.path.join(BASE_DIR, '..', '..', 'contrib', 'dhcp_agent')) +sys.path.append(os.path.join(BASE_DIR, "..", "..", "contrib", "dhcp_agent")) DEBUG = False -TEST_DB_ENGINE = os.environ.get('TEST_DB_ENGINE', 'mysql') -if TEST_DB_ENGINE == 'psql': - DATABASES['default'].update({ - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'PORT': os.environ.get('DATABASE_PORT', 5432), - 'OPTIONS': {}, - }) -elif TEST_DB_ENGINE == 'mysql': - DATABASES['default']['TEST'].update({ - 'CHARSET': 'utf8', - 'COLLATION': 'utf8_general_ci', - }) +TEST_DB_ENGINE = os.environ.get("TEST_DB_ENGINE", "mysql") +if TEST_DB_ENGINE == "psql": + DATABASES["default"].update( + { + "ENGINE": "django.db.backends.postgresql_psycopg2", + "PORT": os.environ.get("DATABASE_PORT", 5432), + "OPTIONS": {}, + } + ) +elif TEST_DB_ENGINE == "mysql": + DATABASES["default"]["TEST"].update( + { + "CHARSET": "utf8", + "COLLATION": "utf8_general_ci", + } + ) INSTALLED_APPS += ( - 'ralph.lib.mixins', - 'ralph.tests', - 'ralph.lib.custom_fields.tests', - 'ralph.lib.permissions.tests', - 'ralph.lib.polymorphic.tests', - 'ralph.lib.mixins.tests', + "ralph.lib.mixins", + "ralph.tests", + "ralph.lib.custom_fields.tests", + "ralph.lib.permissions.tests", + "ralph.lib.polymorphic.tests", + "ralph.lib.mixins.tests", ) USE_CACHE = False -PASSWORD_HASHERS = ('django_plainpasswordhasher.PlainPasswordHasher',) -STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' +PASSWORD_HASHERS = ("django_plainpasswordhasher.PlainPasswordHasher",) +STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage" -ROOT_URLCONF = 'ralph.urls.test' +ROOT_URLCONF = "ralph.urls.test" # specify all url modules to reload during specific tests # see `ralph.tests.mixins.ReloadUrlsMixin` for details -URLCONF_MODULES = ['ralph.urls.base', ROOT_URLCONF] +URLCONF_MODULES = ["ralph.urls.base", ROOT_URLCONF] # Uncomment lines below if you want some additional output from loggers # during tests. @@ -44,31 +48,32 @@ # {'level': 'DEBUG', 'handlers': ['console']} # ) -RQ_QUEUES['ralph_job_test'] = dict(ASYNC=False, **REDIS_CONNECTION) -RQ_QUEUES['ralph_async_transitions']['ASYNC'] = False -RALPH_INTERNAL_SERVICES.update({ - 'JOB_TEST': { - 'queue_name': 'ralph_job_test', - 'method': 'ralph.lib.external_services.tests.test_job_func', +RQ_QUEUES["ralph_job_test"] = dict(ASYNC=False, **REDIS_CONNECTION) +RQ_QUEUES["ralph_async_transitions"]["ASYNC"] = False +RALPH_INTERNAL_SERVICES.update( + { + "JOB_TEST": { + "queue_name": "ralph_job_test", + "method": "ralph.lib.external_services.tests.test_job_func", + } } -}) +) CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - 'LOCATION': 'unique-snowflake', + "default": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + "LOCATION": "unique-snowflake", + }, + "template_fragments": { + "BACKEND": "django.core.cache.backends.dummy.DummyCache", }, - 'template_fragments': { - 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', - } } -SKIP_MIGRATIONS = os.environ.get('SKIP_MIGRATIONS', None) +SKIP_MIGRATIONS = os.environ.get("SKIP_MIGRATIONS", None) if SKIP_MIGRATIONS: - print('skipping migrations') + print("skipping migrations") class DisableMigrations(object): - def __contains__(self, item): return True @@ -77,8 +82,8 @@ def __getitem__(self, item): MIGRATION_MODULES = DisableMigrations() -EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' +EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" ENABLE_EMAIL_NOTIFICATION = True ENABLE_HERMES_INTEGRATION = True -HERMES['ENABLED'] = ENABLE_HERMES_INTEGRATION +HERMES["ENABLED"] = ENABLE_HERMES_INTEGRATION diff --git a/src/ralph/signals.py b/src/ralph/signals.py index 2ac27932c4..223c49034c 100644 --- a/src/ralph/signals.py +++ b/src/ralph/signals.py @@ -39,16 +39,14 @@ def post_commit(func, model, signal=post_save, single_call=True): * if transaction is not started for current request, then this hook will behave as post_save (will be called immediately) """ + @receiver(signal, sender=model, weak=False) def wrap(sender, instance, **kwargs): def wrapper(): # prevent from calling the same func multiple times for single # instance - called_already_attr = '_' + func.__name__ + '_called' - if not ( - getattr(instance, called_already_attr, False) and - single_call - ): + called_already_attr = "_" + func.__name__ + "_called" + if not (getattr(instance, called_already_attr, False) and single_call): func(instance) setattr(instance, called_already_attr, True) diff --git a/src/ralph/sim_cards/admin.py b/src/ralph/sim_cards/admin.py index 7e5e60f849..0b1d1ecd24 100644 --- a/src/ralph/sim_cards/admin.py +++ b/src/ralph/sim_cards/admin.py @@ -1,11 +1,7 @@ from django.utils.translation import ugettext_lazy as _ from ralph.admin.decorators import register -from ralph.admin.mixins import ( - BulkEditChangeListMixin, - RalphAdmin, - RalphAdminMixin -) +from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphAdminMixin from ralph.admin.views.multiadd import MulitiAddAdminMixin from ralph.lib.transitions.admin import TransitionAdminMixin from ralph.sim_cards.forms import SIMCardForm @@ -18,7 +14,7 @@ class SIMCardAdmin( TransitionAdminMixin, RalphAdmin, BulkEditChangeListMixin, - RalphAdminMixin + RalphAdminMixin, ): # NOTE(Anna Gabler): list_display - list on top page # raw_id_fields - fancy autocomplete @@ -26,49 +22,83 @@ class SIMCardAdmin( # list_filter - list of filters on simcard list # fieldsets - configuration of editor layout form = SIMCardForm - actions = ['bulk_edit_action'] + actions = ["bulk_edit_action"] show_transition_history = True - list_display = ['status', 'card_number', 'phone_number', 'pin1', 'puk1', - 'user', 'owner', 'warehouse', 'carrier', - 'quarantine_until', 'property_of'] + list_display = [ + "status", + "card_number", + "phone_number", + "pin1", + "puk1", + "user", + "owner", + "warehouse", + "carrier", + "quarantine_until", + "property_of", + ] multiadd_summary_fields = list_display - raw_id_fields = ['warehouse', 'owner', 'user', 'carrier'] + raw_id_fields = ["warehouse", "owner", "user", "carrier"] - list_select_related = [ - 'user', 'warehouse', 'owner', 'carrier' + list_select_related = ["user", "warehouse", "owner", "carrier"] + search_fields = [ + "card_number", + "phone_number", + "user__first_name", + "user__last_name", + "user__username", ] - search_fields = ['card_number', 'phone_number', 'user__first_name', - 'user__last_name', 'user__username'] - bulk_edit_list = ['status', 'warehouse', 'user', 'owner', 'features'] + bulk_edit_list = ["status", "warehouse", "user", "owner", "features"] list_filter = [ - 'status', 'features', 'phone_number', 'card_number', 'warehouse', - 'user', 'owner', 'user__segment', 'user__company', 'user__department', - 'user__employee_id', 'carrier', 'quarantine_until', 'property_of' + "status", + "features", + "phone_number", + "card_number", + "warehouse", + "user", + "owner", + "user__segment", + "user__company", + "user__department", + "user__employee_id", + "carrier", + "quarantine_until", + "property_of", ] fieldsets = ( - (_('SIM Card Info'), { - 'fields': ( - 'status', 'card_number', 'phone_number', 'pin1', 'puk1', - 'pin2', 'puk2', 'carrier', 'remarks', 'features', 'property_of' - - ) - }), - (_('User Info'), { - 'fields': ( - 'user', 'owner', 'warehouse', 'quarantine_until' - ) - }), + ( + _("SIM Card Info"), + { + "fields": ( + "status", + "card_number", + "phone_number", + "pin1", + "puk1", + "pin2", + "puk2", + "carrier", + "remarks", + "features", + "property_of", + ) + }, + ), + ( + _("User Info"), + {"fields": ("user", "owner", "warehouse", "quarantine_until")}, + ), ) def get_multiadd_fields(self, obj=None): multi_add_fields = [ - {'field': 'card_number', 'allow_duplicates': False}, - {'field': 'phone_number', 'allow_duplicates': False}, - {'field': 'pin1', 'allow_duplicates': True}, - {'field': 'puk1', 'allow_duplicates': True}, + {"field": "card_number", "allow_duplicates": False}, + {"field": "phone_number", "allow_duplicates": False}, + {"field": "pin1", "allow_duplicates": True}, + {"field": "puk1", "allow_duplicates": True}, ] return multi_add_fields @@ -81,4 +111,4 @@ class SIMCardFeaturesAdmin(RalphAdmin): @register(CellularCarrier) class CellularCarrierAdmin(RalphAdmin): - list_display = ['name'] + list_display = ["name"] diff --git a/src/ralph/sim_cards/api.py b/src/ralph/sim_cards/api.py index 3f2e4fba06..761a9679fc 100644 --- a/src/ralph/sim_cards/api.py +++ b/src/ralph/sim_cards/api.py @@ -7,13 +7,13 @@ class CellularCarrierSerializer(RalphAPISerializer): class Meta: model = CellularCarrier - fields = ['name'] + fields = ["name"] class SIMCardFeaturesSerializer(RalphAPISerializer): class Meta: model = SIMCardFeatures - fields = ['name'] + fields = ["name"] class SIMCardSerializer(RalphAPISerializer): @@ -24,9 +24,20 @@ class SIMCardSerializer(RalphAPISerializer): class Meta: model = SIMCard - fields = ['status', 'card_number', 'phone_number', 'pin1', 'puk1', - 'user', 'owner', 'warehouse', 'carrier', 'features', - 'quarantine_until', 'modified'] + fields = [ + "status", + "card_number", + "phone_number", + "pin1", + "puk1", + "user", + "owner", + "warehouse", + "carrier", + "features", + "quarantine_until", + "modified", + ] class CellularCarrierViewSet(RalphAPIViewSet): @@ -42,13 +53,17 @@ class SIMCardFeatureViewSet(RalphAPIViewSet): class SIMCardViewSet(RalphAPIViewSet): queryset = SIMCard.objects.all() serializer_class = SIMCardSerializer - select_related = ['carrier', 'user', 'owner'] - prefetch_related = ['features'] - filter_fields = ['user__username', 'features__name', 'owner__username', - 'carrier__name'] + select_related = ["carrier", "user", "owner"] + prefetch_related = ["features"] + filter_fields = [ + "user__username", + "features__name", + "owner__username", + "carrier__name", + ] -router.register(r'sim-card-feature', SIMCardFeatureViewSet) -router.register(r'sim-card-cellular-carrier', CellularCarrierViewSet) -router.register(r'sim-card', SIMCardViewSet) +router.register(r"sim-card-feature", SIMCardFeatureViewSet) +router.register(r"sim-card-cellular-carrier", CellularCarrierViewSet) +router.register(r"sim-card", SIMCardViewSet) urlpatterns = [] diff --git a/src/ralph/sim_cards/forms.py b/src/ralph/sim_cards/forms.py index 9474cf85f8..f5e558ddcb 100644 --- a/src/ralph/sim_cards/forms.py +++ b/src/ralph/sim_cards/forms.py @@ -9,5 +9,5 @@ class Meta: model = SIMCard exclude = [] widgets = { - 'features': CheckboxSelectMultiple, + "features": CheckboxSelectMultiple, } diff --git a/src/ralph/sim_cards/migrations/0001_initial.py b/src/ralph/sim_cards/migrations/0001_initial.py index 4b46bf58e6..1e6a13e81e 100644 --- a/src/ralph/sim_cards/migrations/0001_initial.py +++ b/src/ralph/sim_cards/migrations/0001_initial.py @@ -10,48 +10,214 @@ class Migration(migrations.Migration): - dependencies = [ - ('back_office', '0009_auto_20181016_1252'), + ("back_office", "0009_auto_20181016_1252"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='CellularCarrier', + name="CellularCarrier", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('name', models.CharField(verbose_name='name', max_length=255, unique=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", max_length=255, unique=True), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='SIMCard', + name="SIMCard", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), - ('pin1', models.CharField(max_length=8, blank=True, null=True, help_text='Required numeric characters only.', validators=[django.core.validators.MinLengthValidator(4), django.core.validators.RegexValidator(regex='^\\d+$', message='Required numeric characters only.')])), - ('puk1', models.CharField(max_length=16, help_text='Required numeric characters only.', validators=[django.core.validators.MinLengthValidator(5), django.core.validators.RegexValidator(regex='^\\d+$', message='Required numeric characters only.')])), - ('pin2', models.CharField(max_length=8, blank=True, null=True, help_text='Required numeric characters only.', validators=[django.core.validators.MinLengthValidator(4), django.core.validators.RegexValidator(regex='^\\d+$', message='Required numeric characters only.')])), - ('puk2', models.CharField(max_length=16, blank=True, null=True, help_text='Required numeric characters only.', validators=[django.core.validators.MinLengthValidator(5), django.core.validators.RegexValidator(regex='^\\d+$', message='Required numeric characters only.')])), - ('card_number', models.CharField(max_length=22, unique=True, validators=[django.core.validators.MinLengthValidator(1), django.core.validators.MaxLengthValidator(22), django.core.validators.RegexValidator(regex='^\\d+$', message='Required numeric characters only.')])), - ('phone_number', models.CharField(max_length=16, unique=True, help_text='ex. +2920181234', validators=[django.core.validators.MinLengthValidator(1), django.core.validators.MaxLengthValidator(16), django.core.validators.RegexValidator(regex='^\\+\\d+$', message='Phone number must have +2920181234 format.')])), - ('status', ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in progress'), (3, 'waiting for release'), (4, 'in use'), (5, 'damaged'), (6, 'liquidated'), (7, 'free'), (8, 'reserved'), (9, 'loan in progress'), (10, 'return in progress'), (11, 'in quarantine')])), - ('remarks', models.TextField(blank=True)), - ('quarantine_until', models.DateField(blank=True, null=True, help_text='End of quarantine date.')), - ('carrier', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='sim_cards.CellularCarrier')), - ('owner', models.ForeignKey(blank=True, null=True, related_name='owned_simcards', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('user', models.ForeignKey(blank=True, null=True, related_name='used_simcards', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='back_office.Warehouse')), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), + ( + "pin1", + models.CharField( + max_length=8, + blank=True, + null=True, + help_text="Required numeric characters only.", + validators=[ + django.core.validators.MinLengthValidator(4), + django.core.validators.RegexValidator( + regex="^\\d+$", + message="Required numeric characters only.", + ), + ], + ), + ), + ( + "puk1", + models.CharField( + max_length=16, + help_text="Required numeric characters only.", + validators=[ + django.core.validators.MinLengthValidator(5), + django.core.validators.RegexValidator( + regex="^\\d+$", + message="Required numeric characters only.", + ), + ], + ), + ), + ( + "pin2", + models.CharField( + max_length=8, + blank=True, + null=True, + help_text="Required numeric characters only.", + validators=[ + django.core.validators.MinLengthValidator(4), + django.core.validators.RegexValidator( + regex="^\\d+$", + message="Required numeric characters only.", + ), + ], + ), + ), + ( + "puk2", + models.CharField( + max_length=16, + blank=True, + null=True, + help_text="Required numeric characters only.", + validators=[ + django.core.validators.MinLengthValidator(5), + django.core.validators.RegexValidator( + regex="^\\d+$", + message="Required numeric characters only.", + ), + ], + ), + ), + ( + "card_number", + models.CharField( + max_length=22, + unique=True, + validators=[ + django.core.validators.MinLengthValidator(1), + django.core.validators.MaxLengthValidator(22), + django.core.validators.RegexValidator( + regex="^\\d+$", + message="Required numeric characters only.", + ), + ], + ), + ), + ( + "phone_number", + models.CharField( + max_length=16, + unique=True, + help_text="ex. +2920181234", + validators=[ + django.core.validators.MinLengthValidator(1), + django.core.validators.MaxLengthValidator(16), + django.core.validators.RegexValidator( + regex="^\\+\\d+$", + message="Phone number must have +2920181234 format.", + ), + ], + ), + ), + ( + "status", + ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in progress"), + (3, "waiting for release"), + (4, "in use"), + (5, "damaged"), + (6, "liquidated"), + (7, "free"), + (8, "reserved"), + (9, "loan in progress"), + (10, "return in progress"), + (11, "in quarantine"), + ], + ), + ), + ("remarks", models.TextField(blank=True)), + ( + "quarantine_until", + models.DateField( + blank=True, null=True, help_text="End of quarantine date." + ), + ), + ( + "carrier", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="sim_cards.CellularCarrier", + ), + ), + ( + "owner", + models.ForeignKey( + blank=True, + null=True, + related_name="owned_simcards", + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + related_name="used_simcards", + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "warehouse", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="back_office.Warehouse", + ), + ), ], options={ - 'ordering': ('-modified', '-created'), - 'abstract': False, + "ordering": ("-modified", "-created"), + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), diff --git a/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py b/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py index 685ea0176a..47c9b8a187 100644 --- a/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py +++ b/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py @@ -6,27 +6,37 @@ class Migration(migrations.Migration): - dependencies = [ - ('sim_cards', '0001_initial'), + ("sim_cards", "0001_initial"), ] operations = [ migrations.CreateModel( - name='SIMCardFeatures', + name="SIMCardFeatures", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('name', models.CharField(verbose_name='name', max_length=255, unique=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", max_length=255, unique=True), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.AddField( - model_name='simcard', - name='features', - field=models.ManyToManyField(blank=True, to='sim_cards.SIMCardFeatures'), + model_name="simcard", + name="features", + field=models.ManyToManyField(blank=True, to="sim_cards.SIMCardFeatures"), ), ] diff --git a/src/ralph/sim_cards/migrations/0003_auto_20181212_1254.py b/src/ralph/sim_cards/migrations/0003_auto_20181212_1254.py index 196dfefa0d..138eb9ae20 100644 --- a/src/ralph/sim_cards/migrations/0003_auto_20181212_1254.py +++ b/src/ralph/sim_cards/migrations/0003_auto_20181212_1254.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('sim_cards', '0002_auto_20181123_1138'), + ("sim_cards", "0002_auto_20181123_1138"), ] operations = [ migrations.AlterModelOptions( - name='simcard', - options={'ordering': ('-modified', '-created')}, + name="simcard", + options={"ordering": ("-modified", "-created")}, ), ] diff --git a/src/ralph/sim_cards/migrations/0004_simcard_property_of.py b/src/ralph/sim_cards/migrations/0004_simcard_property_of.py index 7bc037dddc..fba49695fb 100644 --- a/src/ralph/sim_cards/migrations/0004_simcard_property_of.py +++ b/src/ralph/sim_cards/migrations/0004_simcard_property_of.py @@ -6,16 +6,20 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0032_auto_20200909_1012'), - ('sim_cards', '0003_auto_20181212_1254'), + ("assets", "0032_auto_20200909_1012"), + ("sim_cards", "0003_auto_20181212_1254"), ] operations = [ migrations.AddField( - model_name='simcard', - name='property_of', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='assets.AssetHolder'), + model_name="simcard", + name="property_of", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="assets.AssetHolder", + ), ), ] diff --git a/src/ralph/sim_cards/models.py b/src/ralph/sim_cards/models.py index 9a81fc7ba6..42a642f15d 100644 --- a/src/ralph/sim_cards/models.py +++ b/src/ralph/sim_cards/models.py @@ -9,7 +9,7 @@ from django.core.validators import ( MaxLengthValidator, MinLengthValidator, - RegexValidator + RegexValidator, ) from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -18,11 +18,7 @@ from ralph.attachments.utils import send_transition_attachments_to_user from ralph.back_office.models import autocomplete_user, Warehouse from ralph.lib.hooks import get_hook -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin from ralph.lib.transitions.conf import get_report_name_for_transition_id from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.fields import TransitionField @@ -32,19 +28,13 @@ PUK_CODE_VALIDATORS = [ MinLengthValidator(5), - RegexValidator( - regex=r'^\d+$', - message=_('Required numeric characters only.') - ), + RegexValidator(regex=r"^\d+$", message=_("Required numeric characters only.")), ] PIN_CODE_VALIDATORS = [ MinLengthValidator(4), - RegexValidator( - regex=r'^\d+$', - message=_('Required numeric characters only.') - ), + RegexValidator(regex=r"^\d+$", message=_("Required numeric characters only.")), ] @@ -68,69 +58,84 @@ class CellularCarrier(AdminAbsoluteUrlMixin, NamedMixin, models.Model): pass -class SIMCardFeatures( - AdminAbsoluteUrlMixin, - NamedMixin, - models.Model -): +class SIMCardFeatures(AdminAbsoluteUrlMixin, NamedMixin, models.Model): pass -class SIMCard(AdminAbsoluteUrlMixin, TimeStampMixin, models.Model, - metaclass=TransitionWorkflowBase): +class SIMCard( + AdminAbsoluteUrlMixin, + TimeStampMixin, + models.Model, + metaclass=TransitionWorkflowBase, +): pin1 = models.CharField( - max_length=8, null=True, blank=True, - help_text=_('Required numeric characters only.'), - validators=PIN_CODE_VALIDATORS + max_length=8, + null=True, + blank=True, + help_text=_("Required numeric characters only."), + validators=PIN_CODE_VALIDATORS, ) puk1 = models.CharField( - max_length=16, help_text=_('Required numeric characters only.'), - validators=PUK_CODE_VALIDATORS + max_length=16, + help_text=_("Required numeric characters only."), + validators=PUK_CODE_VALIDATORS, ) pin2 = models.CharField( - max_length=8, null=True, blank=True, - help_text=_('Required numeric characters only.'), - validators=PIN_CODE_VALIDATORS + max_length=8, + null=True, + blank=True, + help_text=_("Required numeric characters only."), + validators=PIN_CODE_VALIDATORS, ) puk2 = models.CharField( - max_length=16, null=True, blank=True, - help_text=_('Required numeric characters only.'), - validators=PUK_CODE_VALIDATORS) + max_length=16, + null=True, + blank=True, + help_text=_("Required numeric characters only."), + validators=PUK_CODE_VALIDATORS, + ) carrier = models.ForeignKey( - CellularCarrier, on_delete=models.PROTECT, + CellularCarrier, + on_delete=models.PROTECT, ) card_number = models.CharField( - max_length=22, unique=True, + max_length=22, + unique=True, validators=[ MinLengthValidator(1), MaxLengthValidator(22), RegexValidator( - regex=r'^\d+$', - message=_('Required numeric characters only.'), - ) - ] + regex=r"^\d+$", + message=_("Required numeric characters only."), + ), + ], ) phone_number = models.CharField( - max_length=16, unique=True, help_text=_('ex. +2920181234'), + max_length=16, + unique=True, + help_text=_("ex. +2920181234"), validators=[ MinLengthValidator(1), MaxLengthValidator(16), RegexValidator( - regex=r'^\+\d+$', - message='Phone number must have +2920181234 format.' - ) - ] + regex=r"^\+\d+$", message="Phone number must have +2920181234 format." + ), + ], ) warehouse = models.ForeignKey(Warehouse, on_delete=models.PROTECT) owner = models.ForeignKey( - settings.AUTH_USER_MODEL, null=True, blank=True, + settings.AUTH_USER_MODEL, + null=True, + blank=True, on_delete=models.SET_NULL, - related_name='owned_simcards', + related_name="owned_simcards", ) user = models.ForeignKey( - settings.AUTH_USER_MODEL, null=True, blank=True, + settings.AUTH_USER_MODEL, + null=True, + blank=True, on_delete=models.SET_NULL, - related_name='used_simcards', + related_name="used_simcards", ) status = TransitionField( default=SIMCardStatus.new.id, @@ -138,8 +143,7 @@ class SIMCard(AdminAbsoluteUrlMixin, TimeStampMixin, models.Model, ) remarks = models.TextField(blank=True) quarantine_until = models.DateField( - null=True, blank=True, - help_text=_('End of quarantine date.') + null=True, blank=True, help_text=_("End of quarantine date.") ) features = models.ManyToManyField( SIMCardFeatures, @@ -153,32 +157,31 @@ class SIMCard(AdminAbsoluteUrlMixin, TimeStampMixin, models.Model, ) def __str__(self): - return _('SIM Card: {}').format(self.phone_number) + return _("SIM Card: {}").format(self.phone_number) @classmethod @transition_action( form_fields={ - 'user': { - 'field': forms.CharField(label=_('User')), - 'autocomplete_field': 'user', - 'default_value': partial(autocomplete_user, field_name='user') + "user": { + "field": forms.CharField(label=_("User")), + "autocomplete_field": "user", + "default_value": partial(autocomplete_user, field_name="user"), } }, - run_after=['unassign_user'] + run_after=["unassign_user"], ) def assign_user(cls, instances, **kwargs): - user = get_user_model().objects.get(pk=int(kwargs['user'])) + user = get_user_model().objects.get(pk=int(kwargs["user"])) for instance in instances: instance.user = user @classmethod @transition_action( form_fields={ - 'accept': { - 'field': forms.BooleanField( + "accept": { + "field": forms.BooleanField( label=_( - 'I have read and fully understand and ' - 'accept the agreement.' + "I have read and fully understand and " "accept the agreement." ) ) }, @@ -190,44 +193,44 @@ def accept_asset_release_agreement(cls, instances, requester, **kwargs): @classmethod @transition_action( form_fields={ - 'report_language': { - 'field': forms.ModelChoiceField( - label=_('Release report language'), - queryset=ReportLanguage.objects.all().order_by('-default'), - empty_label=None + "report_language": { + "field": forms.ModelChoiceField( + label=_("Release report language"), + queryset=ReportLanguage.objects.all().order_by("-default"), + empty_label=None, ), - 'exclude_from_history': True + "exclude_from_history": True, } }, return_attachment=True, - run_after=['assign_owner', 'assign_user'] + run_after=["assign_owner", "assign_user"], ) def release_report(cls, instances, requester, transition_id, **kwargs): report_name = get_report_name_for_transition_id(transition_id) return generate_report( - instances=instances, name=report_name, requester=requester, - language=kwargs['report_language'], - context=cls._get_report_context(instances) + instances=instances, + name=report_name, + requester=requester, + language=kwargs["report_language"], + context=cls._get_report_context(instances), ) @classmethod def _get_report_context(cls, instances): context = [ { - 'card_number': obj.card_number, - 'carrier': obj.carrier.name, - 'pin1': obj.pin1, - 'puk1': obj.puk1, - 'phone_number': obj.phone_number, + "card_number": obj.card_number, + "carrier": obj.carrier.name, + "pin1": obj.pin1, + "puk1": obj.puk1, + "phone_number": obj.phone_number, } for obj in instances ] return context @classmethod - @transition_action( - run_after=['release_report'] - ) + @transition_action(run_after=["release_report"]) def assign_requester_as_an_owner(cls, instances, requester, **kwargs): """Assign current user as an owner""" for instance in instances: @@ -237,143 +240,130 @@ def assign_requester_as_an_owner(cls, instances, requester, **kwargs): @classmethod @transition_action( form_fields={ - 'owner': { - 'field': forms.CharField(label=_('Owner')), - 'autocomplete_field': 'owner', - 'default_value': partial(autocomplete_user, field_name='owner') + "owner": { + "field": forms.CharField(label=_("Owner")), + "autocomplete_field": "owner", + "default_value": partial(autocomplete_user, field_name="owner"), } }, - help_text=_('assign owner'), - run_after=['unassign_owner'] + help_text=_("assign owner"), + run_after=["unassign_owner"], ) def assign_owner(cls, instances, **kwargs): - owner = get_user_model().objects.get(pk=int(kwargs['owner'])) + owner = get_user_model().objects.get(pk=int(kwargs["owner"])) for instance in instances: instance.owner = owner @classmethod - @transition_action(run_after=['release_report']) - def send_attachments_to_user( - cls, requester, transition_id, **kwargs - ): - context_func = get_hook( - 'back_office.transition_action.email_context' - ) + @transition_action(run_after=["release_report"]) + def send_attachments_to_user(cls, requester, transition_id, **kwargs): + context_func = get_hook("back_office.transition_action.email_context") send_transition_attachments_to_user( requester=requester, transition_id=transition_id, context_func=context_func, - **kwargs + **kwargs, ) @classmethod @transition_action( form_fields={ - 'warehouse': { - 'field': forms.CharField(label=_('Warehouse')), - 'autocomplete_field': 'warehouse', - 'default_value': partial( - autocomplete_user, - field_name='warehouse' - ) + "warehouse": { + "field": forms.CharField(label=_("Warehouse")), + "autocomplete_field": "warehouse", + "default_value": partial(autocomplete_user, field_name="warehouse"), } } ) def assign_warehouse(cls, instances, **kwargs): - warehouse = Warehouse.objects.get(pk=int(kwargs['warehouse'])) + warehouse = Warehouse.objects.get(pk=int(kwargs["warehouse"])) for instance in instances: instance.warehouse = warehouse @classmethod - @transition_action( - run_after=['loan_report', 'return_report'] - ) + @transition_action(run_after=["loan_report", "return_report"]) def unassign_owner(cls, instances, **kwargs): for instance in instances: - kwargs['history_kwargs'][instance.pk][ - 'affected_owner' - ] = str(instance.owner) + kwargs["history_kwargs"][instance.pk]["affected_owner"] = str( + instance.owner + ) instance.owner = None @classmethod - @transition_action( - run_after=['loan_report', 'return_report'] - ) + @transition_action(run_after=["loan_report", "return_report"]) def unassign_user(cls, instances, **kwargs): for instance in instances: - kwargs['history_kwargs'][instance.pk][ - 'affected_user' - ] = str(instance.user) + kwargs["history_kwargs"][instance.pk]["affected_user"] = str(instance.user) instance.user = None @classmethod @transition_action( form_fields={ - 'task_url': { - 'field': forms.URLField(label=_('task URL')), + "task_url": { + "field": forms.URLField(label=_("task URL")), } } ) def assign_task_url(cls, instances, **kwargs): for instance in instances: - instance.task_url = kwargs['task_url'] + instance.task_url = kwargs["task_url"] @classmethod @transition_action() def quarantine_date(cls, instances, **kwargs): for instance in instances: - instance.quarantine_until = datetime.date.today() + datetime.timedelta(days=90) # noqa + instance.quarantine_until = datetime.date.today() + datetime.timedelta( + days=90 + ) # noqa @classmethod @transition_action( form_fields={ - 'pin1': { - 'field': forms.CharField(label=_('pin1')), + "pin1": { + "field": forms.CharField(label=_("pin1")), + }, + "puk1": { + "field": forms.CharField(label=_("puk1")), }, - 'puk1': { - 'field': forms.CharField(label=_('puk1')), - } } ) def change_pin_and_puk(cls, instances, **kwargs): for instance in instances: - instance.pin1 = kwargs['pin1'] - instance.puk1 = kwargs['puk1'] + instance.pin1 = kwargs["pin1"] + instance.puk1 = kwargs["puk1"] @classmethod @transition_action( form_fields={ - 'card number': { - 'field': forms.CharField(label=_('card number')), + "card number": { + "field": forms.CharField(label=_("card number")), } } ) def card_number_to_notes(cls, instances, **kwargs): for instance in instances: - instance.remarks = '{}\n{}'.format( - instance.remarks, instance.card_number - ) - instance.card_number = kwargs['card number'] + instance.remarks = "{}\n{}".format(instance.remarks, instance.card_number) + instance.card_number = kwargs["card number"] @classmethod @transition_action( form_fields={ - 'user': { - 'field': forms.CharField(label=_('User')), - 'autocomplete_field': 'user', + "user": { + "field": forms.CharField(label=_("User")), + "autocomplete_field": "user", + }, + "owner": { + "field": forms.CharField(label=_("Owner")), + "autocomplete_field": "owner", + "condition": lambda obj, actions: bool(obj.owner), }, - 'owner': { - 'field': forms.CharField(label=_('Owner')), - 'autocomplete_field': 'owner', - 'condition': lambda obj, actions: bool(obj.owner), - } } ) def change_user_and_owner(cls, instances, **kwargs): UserModel = get_user_model() # noqa - user_id = kwargs.get('user', None) + user_id = kwargs.get("user", None) user = UserModel.objects.get(id=user_id) - owner_id = kwargs.get('owner', None) + owner_id = kwargs.get("owner", None) for instance in instances: instance.user = user if not owner_id: diff --git a/src/ralph/sim_cards/tests/factories.py b/src/ralph/sim_cards/tests/factories.py index 7854b2ee78..38e6a26f9e 100644 --- a/src/ralph/sim_cards/tests/factories.py +++ b/src/ralph/sim_cards/tests/factories.py @@ -4,38 +4,36 @@ from ralph.back_office.models import BackOfficeAssetStatus from ralph.back_office.tests.factories import WarehouseFactory from ralph.sim_cards.models import CellularCarrier, SIMCard, SIMCardFeatures -from ralph.tests.factories import UserFactory class CellularCarrierFactory(DjangoModelFactory): - name = factory.Iterator(['Mobile One', 'Mobile Two', 'Mobile T']) + name = factory.Iterator(["Mobile One", "Mobile Two", "Mobile T"]) class Meta: model = CellularCarrier - django_get_or_create = ['name'] + django_get_or_create = ["name"] class SIMCardFeatureFactory(DjangoModelFactory): - name = factory.Iterator(['Feature {}'.format(a) for a in range(50)]) + name = factory.Iterator(["Feature {}".format(a) for a in range(50)]) class Meta: model = SIMCardFeatures - django_get_or_create = ['name'] + django_get_or_create = ["name"] class SIMCardFactory(DjangoModelFactory): - - remarks = factory.Sequence(lambda n: 'Generated factory {}'.format(n)) - pin1 = factory.Sequence(lambda n: '0000{}'.format(n)) - pin2 = factory.Sequence(lambda n: '0000{}'.format(n)) - puk1 = factory.Sequence(lambda n: '00000000{}'.format(n)) - puk2 = factory.Sequence(lambda n: '00000000{}'.format(n)) - card_number = factory.Sequence(lambda n: '00{}000{}000'.format(n, n)) - phone_number = factory.Sequence(lambda n: '+48{}000{}000'.format(n, n)) + remarks = factory.Sequence(lambda n: "Generated factory {}".format(n)) + pin1 = factory.Sequence(lambda n: "0000{}".format(n)) + pin2 = factory.Sequence(lambda n: "0000{}".format(n)) + puk1 = factory.Sequence(lambda n: "00000000{}".format(n)) + puk2 = factory.Sequence(lambda n: "00000000{}".format(n)) + card_number = factory.Sequence(lambda n: "00{}000{}000".format(n, n)) + phone_number = factory.Sequence(lambda n: "+48{}000{}000".format(n, n)) warehouse = factory.SubFactory(WarehouseFactory) carrier = factory.SubFactory(CellularCarrierFactory) status = BackOfficeAssetStatus.new class Meta: model = SIMCard - django_get_or_create = ['card_number'] + django_get_or_create = ["card_number"] diff --git a/src/ralph/sim_cards/tests/test_admin.py b/src/ralph/sim_cards/tests/test_admin.py index 7a00b57635..0939090192 100644 --- a/src/ralph/sim_cards/tests/test_admin.py +++ b/src/ralph/sim_cards/tests/test_admin.py @@ -5,7 +5,7 @@ from ralph.sim_cards.models import SIMCard from ralph.sim_cards.tests.factories import ( CellularCarrierFactory, - SIMCardFeatureFactory + SIMCardFeatureFactory, ) from ralph.tests.base import RalphTestCase from ralph.tests.factories import UserFactory @@ -28,38 +28,33 @@ def test_create_correct_data(self): expected_features_id = sorted(f.pk for f in features) sim_card_data = { - 'status': BackOfficeAssetStatus.new.id, - 'pin1': '1234', - 'pin2': '5678', - 'puk1': '12346', - 'puk2': '56786', - 'card_number': '1938462528298', - 'phone_number': '+4812345678911', - 'warehouse': warehouse.pk, - 'user': user.pk, - 'owner': owner.pk, - 'carrier': carrier.pk, - 'features': expected_features_id + "status": BackOfficeAssetStatus.new.id, + "pin1": "1234", + "pin2": "5678", + "puk1": "12346", + "puk2": "56786", + "card_number": "1938462528298", + "phone_number": "+4812345678911", + "warehouse": warehouse.pk, + "user": user.pk, + "owner": owner.pk, + "carrier": carrier.pk, + "features": expected_features_id, } - url = reverse('admin:sim_cards_simcard_add') + url = reverse("admin:sim_cards_simcard_add") response = self.client.post(url, sim_card_data, follow=True) - self.assertNotIn('errors', response.context_data) + self.assertNotIn("errors", response.context_data) - sim_card_qs = SIMCard.objects.filter( - card_number=sim_card_data['card_number'] - ) + sim_card_qs = SIMCard.objects.filter(card_number=sim_card_data["card_number"]) self.assertTrue(sim_card_qs.exists()) created_sim_card = sim_card_qs.first() - assigned_features = sorted( - f.pk for f in created_sim_card.features.all() - ) + assigned_features = sorted(f.pk for f in created_sim_card.features.all()) self.assertEqual(expected_features_id, assigned_features) - def test_create_incorrect_data(self): carrier = CellularCarrierFactory() @@ -70,21 +65,20 @@ def test_create_incorrect_data(self): owner = UserFactory() sim_card_data = { - 'status': BackOfficeAssetStatus.new, - 'pin1': '12343777448484', - 'pin2': '568fg458', - 'puk1': '123456789123456', - 'puk2': '567hdj8', - 'card_number': '1938462hdhd98', - 'phone_number': '481234568911', - 'warehouse': warehouse.pk, - 'user': user.pk, - 'owner': owner.pk, - 'carrier': carrier.pk, - + "status": BackOfficeAssetStatus.new, + "pin1": "12343777448484", + "pin2": "568fg458", + "puk1": "123456789123456", + "puk2": "567hdj8", + "card_number": "1938462hdhd98", + "phone_number": "481234568911", + "warehouse": warehouse.pk, + "user": user.pk, + "owner": owner.pk, + "carrier": carrier.pk, } - url = reverse('admin:sim_cards_simcard_add') + url = reverse("admin:sim_cards_simcard_add") response = self.client.post(url, sim_card_data, follow=True) - self.assertIn('errors', response.context_data) - self.assertEqual(6, len(response.context_data['errors'])) + self.assertIn("errors", response.context_data) + self.assertEqual(6, len(response.context_data["errors"])) diff --git a/src/ralph/ssl_certificates/__init__.py b/src/ralph/ssl_certificates/__init__.py index eb89e7ddb6..41687bb7dc 100644 --- a/src/ralph/ssl_certificates/__init__.py +++ b/src/ralph/ssl_certificates/__init__.py @@ -1 +1 @@ -default_app_config = 'ralph.ssl_certificates.apps.SSLCertificates' +default_app_config = "ralph.ssl_certificates.apps.SSLCertificates" diff --git a/src/ralph/ssl_certificates/admin.py b/src/ralph/ssl_certificates/admin.py index c2d6a16e31..5ab9defdb6 100644 --- a/src/ralph/ssl_certificates/admin.py +++ b/src/ralph/ssl_certificates/admin.py @@ -12,37 +12,52 @@ class SSLCertificateAdmin(AttachmentsMixin, RalphAdmin): form = SSLCertificateForm list_select_related = [ - 'issued_by', + "issued_by", ] list_filter = [ - 'name', 'certificate_type', - ('date_from', DateListFilter), - ('date_to', DateListFilter), 'issued_by', - 'service_env', 'certificate_repository' + "name", + "certificate_type", + ("date_from", DateListFilter), + ("date_to", DateListFilter), + "issued_by", + "service_env", + "certificate_repository", ] list_display = [ - 'name', 'domain_ssl', 'issued_by', - 'date_from', 'date_to', 'certificate_repository' + "name", + "domain_ssl", + "issued_by", + "date_from", + "date_to", + "certificate_repository", ] raw_id_fields = [ - 'issued_by', 'service_env', + "issued_by", + "service_env", ] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', 'domain_ssl', 'certificate_type', - 'issued_by', 'san', 'price', 'date_from', 'date_to', - 'certificate_repository' - ) - }), - (_('Ownership info'), { - 'fields': ( - 'service_env', - ) - }) + ( + _("Basic info"), + { + "fields": ( + "name", + "domain_ssl", + "certificate_type", + "issued_by", + "san", + "price", + "date_from", + "date_to", + "certificate_repository", + ) + }, + ), + (_("Ownership info"), {"fields": ("service_env",)}), ) - search_fields = ['name', ] + search_fields = [ + "name", + ] diff --git a/src/ralph/ssl_certificates/api.py b/src/ralph/ssl_certificates/api.py index ce5307ed4c..3b6dd82869 100644 --- a/src/ralph/ssl_certificates/api.py +++ b/src/ralph/ssl_certificates/api.py @@ -7,7 +7,7 @@ class SSLCertificateSerializer(BaseObjectSerializer): class Meta: model = SSLCertificate depth = 2 - exclude = ('content_type', ) + exclude = ("content_type",) _skip_tags_field = True @@ -15,16 +15,19 @@ class SSLCertificateViewSet(RalphAPIViewSet): queryset = SSLCertificate.objects.all() serializer_class = SSLCertificateSerializer filter_fields = [ - 'name', 'domain_ssl', 'date_from', 'date_to', 'san', 'price', - 'service_env__service__uid', - 'service_env__service__name', - 'service_env__service__id', - ] - select_related = [ - 'service_env__service', 'service_env__environment' + "name", + "domain_ssl", + "date_from", + "date_to", + "san", + "price", + "service_env__service__uid", + "service_env__service__name", + "service_env__service__id", ] + select_related = ["service_env__service", "service_env__environment"] prefetch_related = ("licences__tags", "tags", "custom_fields", "content_type") -router.register(r'sslcertificates', SSLCertificateViewSet) +router.register(r"sslcertificates", SSLCertificateViewSet) urlpatterns = [] diff --git a/src/ralph/ssl_certificates/apps.py b/src/ralph/ssl_certificates/apps.py index 7c11731ee1..a78d0f3ffc 100644 --- a/src/ralph/ssl_certificates/apps.py +++ b/src/ralph/ssl_certificates/apps.py @@ -2,5 +2,4 @@ class SSLCertificates(RalphAppConfig): - - name = 'ralph.ssl_certificates' + name = "ralph.ssl_certificates" diff --git a/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py b/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py index ec510a2845..89907fb2db 100644 --- a/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py +++ b/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py @@ -14,7 +14,7 @@ from ralph.ssl_certificates.models import CertificateType, SSLCertificate -DEFAULT_ISSUER_NAME = 'CA ENT' +DEFAULT_ISSUER_NAME = "CA ENT" def extract_domain_from_filename(filename): @@ -29,18 +29,18 @@ def get_domain_ssl(cert): domain_subject = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME) try: domain_ssl = domain_subject[0].value - if domain_ssl.startswith('*.'): + if domain_ssl.startswith("*."): domain_ssl = domain_ssl[2:] except IndexError: - domain_ssl = '' + domain_ssl = "" return domain_ssl def get_ssl_type(issuer_name, san, filename): ssl_type = CertificateType.ov.id - if re.match(r'^(wildcard.+)', filename): + if re.match(r"^(wildcard.+)", filename): ssl_type = CertificateType.wildcard.id - elif san is not '': + elif san != "": ssl_type = CertificateType.multisan.id elif issuer_name == DEFAULT_ISSUER_NAME: ssl_type = CertificateType.internal.id @@ -48,11 +48,11 @@ def get_ssl_type(issuer_name, san, filename): class Command(BaseCommand): - help = 'Import data to application from dir' + help = "Import data to application from dir" def add_arguments(self, parser): - parser.add_argument('certs_dir', type=str) - parser.add_argument('repository_name', nargs='?', default='', type=str) + parser.add_argument("certs_dir", type=str) + parser.add_argument("repository_name", nargs="?", default="", type=str) def get_data_from_cert(self, cert, filename, repository_name): """ @@ -70,7 +70,7 @@ def get_data_from_cert(self, cert, filename, repository_name): date_from=(Valid to) March 26, 2021, issued_by=(Issuer name) CA Company: """ - san = '' + san = "" extension = None try: extension = cert.extensions.get_extension_for_oid( @@ -80,18 +80,14 @@ def get_data_from_cert(self, cert, filename, repository_name): pass if extension and extension.value: san = extension.value.get_values_for_type(x509.DNSName) - issuer = cert.issuer.get_attributes_for_oid( - NameOID.ORGANIZATION_NAME - ) + issuer = cert.issuer.get_attributes_for_oid(NameOID.ORGANIZATION_NAME) domain = extract_domain_from_filename(filename) issuer_name = DEFAULT_ISSUER_NAME if issuer and issuer[0].value: issuer_name = issuer[0].value domain_ssl = get_domain_ssl(cert) ssl_type = get_ssl_type(issuer_name, san, filename) - manufacturer, _ = Manufacturer.objects.get_or_create( - name=issuer_name - ) + manufacturer, _ = Manufacturer.objects.get_or_create(name=issuer_name) SSLCertificate.objects.get_or_create( name=domain, domain_ssl=domain_ssl, @@ -100,23 +96,21 @@ def get_data_from_cert(self, cert, filename, repository_name): date_to=cert.not_valid_after, date_from=cert.not_valid_before, issued_by=manufacturer, - certificate_repository=repository_name + certificate_repository=repository_name, ) def handle(self, *args, **options): - certs_dir = options['certs_dir'] - repository_name = options['repository_name'] + certs_dir = options["certs_dir"] + repository_name = options["repository_name"] if not os.path.isdir(certs_dir): self.stdout.write( self.style.ERROR( - 'Dir {} not found. Please check certs_dir option.'.format( - certs_dir - ) + "Dir {} not found. Please check certs_dir option.".format(certs_dir) ) ) return for root, dirs, files in os.walk(certs_dir): - for filename in fnmatch.filter(files, '*.crt'): + for filename in fnmatch.filter(files, "*.crt"): cert = None pem_data = None try: @@ -129,9 +123,7 @@ def handle(self, *args, **options): pem_data.encode(), default_backend() ) except ValueError: - self.stderr.write( - '{}/{} is not valid\n'.format(root, filename) - ) + self.stderr.write("{}/{} is not valid\n".format(root, filename)) continue if cert.not_valid_after < datetime.datetime.now(): continue diff --git a/src/ralph/ssl_certificates/management/commands/update_dns_service_env_from_dnsaas.py b/src/ralph/ssl_certificates/management/commands/update_dns_service_env_from_dnsaas.py index f1d1f2882f..a3583079dd 100644 --- a/src/ralph/ssl_certificates/management/commands/update_dns_service_env_from_dnsaas.py +++ b/src/ralph/ssl_certificates/management/commands/update_dns_service_env_from_dnsaas.py @@ -8,49 +8,41 @@ def checking_type(value): # if record type is conected with mail records, then return empty string. # When we get empty string, management command did not change service env. - if value['type'] in {'MX', 'TXT'}: - domain = '' - elif value['type'] in {'CNAME', 'PTR'}: - domain = value['content'] + if value["type"] in {"MX", "TXT"}: + domain = "" + elif value["type"] in {"CNAME", "PTR"}: + domain = value["content"] else: - domain = value['name'] + domain = value["name"] return domain def ssl_certificates_object_update(domain, service_env): - SSLCertificate.objects.filter( - domain_ssl=domain - ).update( - service_env=service_env - ) + SSLCertificate.objects.filter(domain_ssl=domain).update(service_env=service_env) class Command(BaseCommand): - help = 'Checks the compliance of services in SSL Certificates' + help = "Checks the compliance of services in SSL Certificates" def get_records(self, dnsaas_client): - url = dnsaas_client.build_url('records') - self.update_from_record( - dnsaas_client.get_api_result(url) - ) + url = dnsaas_client.build_url("records") + self.update_from_record(dnsaas_client.get_api_result(url)) def update_from_record(self, result): for value in result: domain = checking_type(value) try: - service_dns = value['service']['name'] + service_dns = value["service"]["name"] except TypeError: continue try: service_env = ServiceEnvironment.objects.get( - service__name=service_dns, environment__name='prod' + service__name=service_dns, environment__name="prod" ) except ServiceEnvironment.DoesNotExist: self.stderr.write( - 'Service with name {} ' - 'and prod environment does not exist'.format( - service_dns - ) + "Service with name {} " + "and prod environment does not exist".format(service_dns) ) else: ssl_certificates_object_update(domain, service_env) diff --git a/src/ralph/ssl_certificates/migrations/0001_initial.py b/src/ralph/ssl_certificates/migrations/0001_initial.py index e3be513e3f..5652075826 100644 --- a/src/ralph/ssl_certificates/migrations/0001_initial.py +++ b/src/ralph/ssl_certificates/migrations/0001_initial.py @@ -8,30 +8,101 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0027_asset_buyout_date'), + ("assets", "0027_asset_buyout_date"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='SSLCertificate', + name="SSLCertificate", fields=[ - ('baseobject_ptr', models.OneToOneField(to='assets.BaseObject', parent_link=True, serialize=False, primary_key=True, auto_created=True, on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(verbose_name='certificate name', help_text='Full certificate name', max_length=255)), - ('certificate_type', models.PositiveIntegerField(choices=[(1, 'EV'), (2, 'OV'), (3, 'DV'), (4, 'Wildcard'), (5, 'Multisan'), (6, 'CA ENT')], default=2)), - ('date_from', models.DateField(null=True, blank=True)), - ('date_to', models.DateField()), - ('san', models.TextField(help_text='All Subject Alternative Names', blank=True)), - ('price', models.DecimalField(decimal_places=2, default=0, null=True, blank=True, max_digits=10)), - ('business_owner', models.ForeignKey(related_name='certificates_business_owner', to=settings.AUTH_USER_MODEL, help_text='Business contact person for a certificate', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE)), - ('issued_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.Manufacturer', null=True, blank=True)), - ('technical_owner', models.ForeignKey(related_name='certificates_technical_owner', to=settings.AUTH_USER_MODEL, help_text='Technical contact person for a certificate', blank=True, null=True, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + to="assets.BaseObject", + parent_link=True, + serialize=False, + primary_key=True, + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "name", + models.CharField( + verbose_name="certificate name", + help_text="Full certificate name", + max_length=255, + ), + ), + ( + "certificate_type", + models.PositiveIntegerField( + choices=[ + (1, "EV"), + (2, "OV"), + (3, "DV"), + (4, "Wildcard"), + (5, "Multisan"), + (6, "CA ENT"), + ], + default=2, + ), + ), + ("date_from", models.DateField(null=True, blank=True)), + ("date_to", models.DateField()), + ( + "san", + models.TextField( + help_text="All Subject Alternative Names", blank=True + ), + ), + ( + "price", + models.DecimalField( + decimal_places=2, + default=0, + null=True, + blank=True, + max_digits=10, + ), + ), + ( + "business_owner", + models.ForeignKey( + related_name="certificates_business_owner", + to=settings.AUTH_USER_MODEL, + help_text="Business contact person for a certificate", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "issued_by", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="assets.Manufacturer", + null=True, + blank=True, + ), + ), + ( + "technical_owner", + models.ForeignKey( + related_name="certificates_technical_owner", + to=settings.AUTH_USER_MODEL, + help_text="Technical contact person for a certificate", + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject'), + bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, "assets.baseobject"), ), ] diff --git a/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py b/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py index 896fe5d93e..88b030d18e 100644 --- a/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py +++ b/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py @@ -6,21 +6,30 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0027_asset_buyout_date'), - ('ssl_certificates', '0001_initial'), + ("assets", "0027_asset_buyout_date"), + ("ssl_certificates", "0001_initial"), ] operations = [ migrations.AddField( - model_name='sslcertificate', - name='domain_ssl', - field=models.CharField(max_length=255, verbose_name='domain name', blank=True, help_text='Full domain name'), + model_name="sslcertificate", + name="domain_ssl", + field=models.CharField( + max_length=255, + verbose_name="domain name", + blank=True, + help_text="Full domain name", + ), ), migrations.AddField( - model_name='sslcertificate', - name='service_environment', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='service_environment', to='assets.ServiceEnvironment', null=True), + model_name="sslcertificate", + name="service_environment", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="service_environment", + to="assets.ServiceEnvironment", + null=True, + ), ), ] diff --git a/src/ralph/ssl_certificates/migrations/0003_remove_sslcertificate_service_environment.py b/src/ralph/ssl_certificates/migrations/0003_remove_sslcertificate_service_environment.py index 57ccde33e0..abcfd419bb 100644 --- a/src/ralph/ssl_certificates/migrations/0003_remove_sslcertificate_service_environment.py +++ b/src/ralph/ssl_certificates/migrations/0003_remove_sslcertificate_service_environment.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('ssl_certificates', '0002_auto_20180522_1244'), + ("ssl_certificates", "0002_auto_20180522_1244"), ] operations = [ migrations.RemoveField( - model_name='sslcertificate', - name='service_environment', + model_name="sslcertificate", + name="service_environment", ), ] diff --git a/src/ralph/ssl_certificates/migrations/0004_auto_20181031_1042.py b/src/ralph/ssl_certificates/migrations/0004_auto_20181031_1042.py index 455f292015..72be458949 100644 --- a/src/ralph/ssl_certificates/migrations/0004_auto_20181031_1042.py +++ b/src/ralph/ssl_certificates/migrations/0004_auto_20181031_1042.py @@ -1,22 +1,21 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('ssl_certificates', '0003_remove_sslcertificate_service_environment'), + ("ssl_certificates", "0003_remove_sslcertificate_service_environment"), ] operations = [ migrations.RemoveField( - model_name='sslcertificate', - name='business_owner', + model_name="sslcertificate", + name="business_owner", ), migrations.RemoveField( - model_name='sslcertificate', - name='technical_owner', + model_name="sslcertificate", + name="technical_owner", ), ] diff --git a/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py b/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py index b93154f4d0..fed493d6d7 100644 --- a/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py +++ b/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py @@ -1,26 +1,227 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import djmoney.models.fields from decimal import Decimal class Migration(migrations.Migration): - dependencies = [ - ('ssl_certificates', '0004_auto_20181031_1042'), + ("ssl_certificates", "0004_auto_20181031_1042"), ] operations = [ migrations.AddField( - model_name='sslcertificate', - name='price_currency', - field=djmoney.models.fields.CurrencyField(max_length=3, default='XXX', editable=False, choices=[('XXX', '---'), ('AED', 'AED'), ('AFN', 'AFN'), ('ALL', 'ALL'), ('AMD', 'AMD'), ('ANG', 'ANG'), ('AOA', 'AOA'), ('ARS', 'ARS'), ('AUD', 'AUD'), ('AWG', 'AWG'), ('AZN', 'AZN'), ('BAM', 'BAM'), ('BBD', 'BBD'), ('BDT', 'BDT'), ('BGN', 'BGN'), ('BHD', 'BHD'), ('BIF', 'BIF'), ('BMD', 'BMD'), ('BND', 'BND'), ('BOB', 'BOB'), ('BOV', 'BOV'), ('BRL', 'BRL'), ('BSD', 'BSD'), ('BTN', 'BTN'), ('BWP', 'BWP'), ('BYN', 'BYN'), ('BYR', 'BYR'), ('BZD', 'BZD'), ('CAD', 'CAD'), ('CDF', 'CDF'), ('CHE', 'CHE'), ('CHF', 'CHF'), ('CHW', 'CHW'), ('CLF', 'CLF'), ('CLP', 'CLP'), ('CNY', 'CNY'), ('COP', 'COP'), ('COU', 'COU'), ('CRC', 'CRC'), ('CUC', 'CUC'), ('CUP', 'CUP'), ('CVE', 'CVE'), ('CZK', 'CZK'), ('DJF', 'DJF'), ('DKK', 'DKK'), ('DOP', 'DOP'), ('DZD', 'DZD'), ('EGP', 'EGP'), ('ERN', 'ERN'), ('ETB', 'ETB'), ('EUR', 'EUR'), ('FJD', 'FJD'), ('FKP', 'FKP'), ('GBP', 'GBP'), ('GEL', 'GEL'), ('GHS', 'GHS'), ('GIP', 'GIP'), ('GMD', 'GMD'), ('GNF', 'GNF'), ('GTQ', 'GTQ'), ('GYD', 'GYD'), ('HKD', 'HKD'), ('HNL', 'HNL'), ('HRK', 'HRK'), ('HTG', 'HTG'), ('HUF', 'HUF'), ('IDR', 'IDR'), ('ILS', 'ILS'), ('IMP', 'IMP'), ('INR', 'INR'), ('IQD', 'IQD'), ('IRR', 'IRR'), ('ISK', 'ISK'), ('JMD', 'JMD'), ('JOD', 'JOD'), ('JPY', 'JPY'), ('KES', 'KES'), ('KGS', 'KGS'), ('KHR', 'KHR'), ('KMF', 'KMF'), ('KPW', 'KPW'), ('KRW', 'KRW'), ('KWD', 'KWD'), ('KYD', 'KYD'), ('KZT', 'KZT'), ('LAK', 'LAK'), ('LBP', 'LBP'), ('LKR', 'LKR'), ('LRD', 'LRD'), ('LSL', 'LSL'), ('LTL', 'LTL'), ('LVL', 'LVL'), ('LYD', 'LYD'), ('MAD', 'MAD'), ('MDL', 'MDL'), ('MGA', 'MGA'), ('MKD', 'MKD'), ('MMK', 'MMK'), ('MNT', 'MNT'), ('MOP', 'MOP'), ('MRO', 'MRO'), ('MUR', 'MUR'), ('MVR', 'MVR'), ('MWK', 'MWK'), ('MXN', 'MXN'), ('MXV', 'MXV'), ('MYR', 'MYR'), ('MZN', 'MZN'), ('NAD', 'NAD'), ('NGN', 'NGN'), ('NIO', 'NIO'), ('NOK', 'NOK'), ('NPR', 'NPR'), ('NZD', 'NZD'), ('OMR', 'OMR'), ('PAB', 'PAB'), ('PEN', 'PEN'), ('PGK', 'PGK'), ('PHP', 'PHP'), ('PKR', 'PKR'), ('PLN', 'PLN'), ('PYG', 'PYG'), ('QAR', 'QAR'), ('RON', 'RON'), ('RSD', 'RSD'), ('RUB', 'RUB'), ('RWF', 'RWF'), ('SAR', 'SAR'), ('SBD', 'SBD'), ('SCR', 'SCR'), ('SDG', 'SDG'), ('SEK', 'SEK'), ('SGD', 'SGD'), ('SHP', 'SHP'), ('SLL', 'SLL'), ('SOS', 'SOS'), ('SRD', 'SRD'), ('SSP', 'SSP'), ('STD', 'STD'), ('SVC', 'SVC'), ('SYP', 'SYP'), ('SZL', 'SZL'), ('THB', 'THB'), ('TJS', 'TJS'), ('TMM', 'TMM'), ('TMT', 'TMT'), ('TND', 'TND'), ('TOP', 'TOP'), ('TRY', 'TRY'), ('TTD', 'TTD'), ('TVD', 'TVD'), ('TWD', 'TWD'), ('TZS', 'TZS'), ('UAH', 'UAH'), ('UGX', 'UGX'), ('USD', 'USD'), ('USN', 'USN'), ('UYI', 'UYI'), ('UYU', 'UYU'), ('UZS', 'UZS'), ('VEF', 'VEF'), ('VND', 'VND'), ('VUV', 'VUV'), ('WST', 'WST'), ('XAF', 'XAF'), ('XAG', 'XAG'), ('XAU', 'XAU'), ('XBA', 'XBA'), ('XBB', 'XBB'), ('XBC', 'XBC'), ('XBD', 'XBD'), ('XCD', 'XCD'), ('XDR', 'XDR'), ('XFO', 'XFO'), ('XFU', 'XFU'), ('XOF', 'XOF'), ('XPD', 'XPD'), ('XPF', 'XPF'), ('XPT', 'XPT'), ('XSU', 'XSU'), ('XTS', 'XTS'), ('XUA', 'XUA'), ('XYZ', 'XYZ'), ('YER', 'YER'), ('ZAR', 'ZAR'), ('ZMK', 'ZMK'), ('ZMW', 'ZMW'), ('ZWD', 'ZWD'), ('ZWL', 'ZWL'), ('ZWN', 'ZWN')]), + model_name="sslcertificate", + name="price_currency", + field=djmoney.models.fields.CurrencyField( + max_length=3, + default="XXX", + editable=False, + choices=[ + ("XXX", "---"), + ("AED", "AED"), + ("AFN", "AFN"), + ("ALL", "ALL"), + ("AMD", "AMD"), + ("ANG", "ANG"), + ("AOA", "AOA"), + ("ARS", "ARS"), + ("AUD", "AUD"), + ("AWG", "AWG"), + ("AZN", "AZN"), + ("BAM", "BAM"), + ("BBD", "BBD"), + ("BDT", "BDT"), + ("BGN", "BGN"), + ("BHD", "BHD"), + ("BIF", "BIF"), + ("BMD", "BMD"), + ("BND", "BND"), + ("BOB", "BOB"), + ("BOV", "BOV"), + ("BRL", "BRL"), + ("BSD", "BSD"), + ("BTN", "BTN"), + ("BWP", "BWP"), + ("BYN", "BYN"), + ("BYR", "BYR"), + ("BZD", "BZD"), + ("CAD", "CAD"), + ("CDF", "CDF"), + ("CHE", "CHE"), + ("CHF", "CHF"), + ("CHW", "CHW"), + ("CLF", "CLF"), + ("CLP", "CLP"), + ("CNY", "CNY"), + ("COP", "COP"), + ("COU", "COU"), + ("CRC", "CRC"), + ("CUC", "CUC"), + ("CUP", "CUP"), + ("CVE", "CVE"), + ("CZK", "CZK"), + ("DJF", "DJF"), + ("DKK", "DKK"), + ("DOP", "DOP"), + ("DZD", "DZD"), + ("EGP", "EGP"), + ("ERN", "ERN"), + ("ETB", "ETB"), + ("EUR", "EUR"), + ("FJD", "FJD"), + ("FKP", "FKP"), + ("GBP", "GBP"), + ("GEL", "GEL"), + ("GHS", "GHS"), + ("GIP", "GIP"), + ("GMD", "GMD"), + ("GNF", "GNF"), + ("GTQ", "GTQ"), + ("GYD", "GYD"), + ("HKD", "HKD"), + ("HNL", "HNL"), + ("HRK", "HRK"), + ("HTG", "HTG"), + ("HUF", "HUF"), + ("IDR", "IDR"), + ("ILS", "ILS"), + ("IMP", "IMP"), + ("INR", "INR"), + ("IQD", "IQD"), + ("IRR", "IRR"), + ("ISK", "ISK"), + ("JMD", "JMD"), + ("JOD", "JOD"), + ("JPY", "JPY"), + ("KES", "KES"), + ("KGS", "KGS"), + ("KHR", "KHR"), + ("KMF", "KMF"), + ("KPW", "KPW"), + ("KRW", "KRW"), + ("KWD", "KWD"), + ("KYD", "KYD"), + ("KZT", "KZT"), + ("LAK", "LAK"), + ("LBP", "LBP"), + ("LKR", "LKR"), + ("LRD", "LRD"), + ("LSL", "LSL"), + ("LTL", "LTL"), + ("LVL", "LVL"), + ("LYD", "LYD"), + ("MAD", "MAD"), + ("MDL", "MDL"), + ("MGA", "MGA"), + ("MKD", "MKD"), + ("MMK", "MMK"), + ("MNT", "MNT"), + ("MOP", "MOP"), + ("MRO", "MRO"), + ("MUR", "MUR"), + ("MVR", "MVR"), + ("MWK", "MWK"), + ("MXN", "MXN"), + ("MXV", "MXV"), + ("MYR", "MYR"), + ("MZN", "MZN"), + ("NAD", "NAD"), + ("NGN", "NGN"), + ("NIO", "NIO"), + ("NOK", "NOK"), + ("NPR", "NPR"), + ("NZD", "NZD"), + ("OMR", "OMR"), + ("PAB", "PAB"), + ("PEN", "PEN"), + ("PGK", "PGK"), + ("PHP", "PHP"), + ("PKR", "PKR"), + ("PLN", "PLN"), + ("PYG", "PYG"), + ("QAR", "QAR"), + ("RON", "RON"), + ("RSD", "RSD"), + ("RUB", "RUB"), + ("RWF", "RWF"), + ("SAR", "SAR"), + ("SBD", "SBD"), + ("SCR", "SCR"), + ("SDG", "SDG"), + ("SEK", "SEK"), + ("SGD", "SGD"), + ("SHP", "SHP"), + ("SLL", "SLL"), + ("SOS", "SOS"), + ("SRD", "SRD"), + ("SSP", "SSP"), + ("STD", "STD"), + ("SVC", "SVC"), + ("SYP", "SYP"), + ("SZL", "SZL"), + ("THB", "THB"), + ("TJS", "TJS"), + ("TMM", "TMM"), + ("TMT", "TMT"), + ("TND", "TND"), + ("TOP", "TOP"), + ("TRY", "TRY"), + ("TTD", "TTD"), + ("TVD", "TVD"), + ("TWD", "TWD"), + ("TZS", "TZS"), + ("UAH", "UAH"), + ("UGX", "UGX"), + ("USD", "USD"), + ("USN", "USN"), + ("UYI", "UYI"), + ("UYU", "UYU"), + ("UZS", "UZS"), + ("VEF", "VEF"), + ("VND", "VND"), + ("VUV", "VUV"), + ("WST", "WST"), + ("XAF", "XAF"), + ("XAG", "XAG"), + ("XAU", "XAU"), + ("XBA", "XBA"), + ("XBB", "XBB"), + ("XBC", "XBC"), + ("XBD", "XBD"), + ("XCD", "XCD"), + ("XDR", "XDR"), + ("XFO", "XFO"), + ("XFU", "XFU"), + ("XOF", "XOF"), + ("XPD", "XPD"), + ("XPF", "XPF"), + ("XPT", "XPT"), + ("XSU", "XSU"), + ("XTS", "XTS"), + ("XUA", "XUA"), + ("XYZ", "XYZ"), + ("YER", "YER"), + ("ZAR", "ZAR"), + ("ZMK", "ZMK"), + ("ZMW", "ZMW"), + ("ZWD", "ZWD"), + ("ZWL", "ZWL"), + ("ZWN", "ZWN"), + ], + ), ), migrations.AlterField( - model_name='sslcertificate', - name='price', - field=djmoney.models.fields.MoneyField(null=True, default=Decimal('0'), max_digits=15, decimal_places=2, default_currency='XXX'), + model_name="sslcertificate", + name="price", + field=djmoney.models.fields.MoneyField( + null=True, + default=Decimal("0"), + max_digits=15, + decimal_places=2, + default_currency="XXX", + ), ), ] diff --git a/src/ralph/ssl_certificates/migrations/0006_sslcertificate_certificate_repository.py b/src/ralph/ssl_certificates/migrations/0006_sslcertificate_certificate_repository.py index 6d37df973e..244ec98645 100644 --- a/src/ralph/ssl_certificates/migrations/0006_sslcertificate_certificate_repository.py +++ b/src/ralph/ssl_certificates/migrations/0006_sslcertificate_certificate_repository.py @@ -5,15 +5,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('ssl_certificates', '0005_auto_20200909_1012'), + ("ssl_certificates", "0005_auto_20200909_1012"), ] operations = [ migrations.AddField( - model_name='sslcertificate', - name='certificate_repository', - field=models.CharField(verbose_name='certificate repository', max_length=255, blank=True, help_text='Certificate source repository'), + model_name="sslcertificate", + name="certificate_repository", + field=models.CharField( + verbose_name="certificate repository", + max_length=255, + blank=True, + help_text="Certificate source repository", + ), ), ] diff --git a/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py b/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py index 23586bf31b..c4e44142ec 100644 --- a/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py +++ b/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py @@ -5,16 +5,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('ssl_certificates', '0006_sslcertificate_certificate_repository'), + ("ssl_certificates", "0006_sslcertificate_certificate_repository"), ] operations = [ migrations.AlterModelManagers( - name='sslcertificate', + name="sslcertificate", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/ssl_certificates/models.py b/src/ralph/ssl_certificates/models.py index 67c340e165..7cf111c098 100644 --- a/src/ralph/ssl_certificates/models.py +++ b/src/ralph/ssl_certificates/models.py @@ -10,35 +10,35 @@ class CertificateType(Choices): _ = Choices.Choice - ev = _('EV') - ov = _('OV') - dv = _('DV') - wildcard = _('Wildcard') - multisan = _('Multisan') - internal = _('CA ENT') + ev = _("EV") + ov = _("OV") + dv = _("DV") + wildcard = _("Wildcard") + multisan = _("Multisan") + internal = _("CA ENT") class SSLCertificate(AdminAbsoluteUrlMixin, PriceMixin, BaseObject): name = models.CharField( - verbose_name=_('certificate name'), - help_text=_('Full certificate name'), - max_length=255 + verbose_name=_("certificate name"), + help_text=_("Full certificate name"), + max_length=255, ) domain_ssl = models.CharField( - verbose_name=_('domain name'), + verbose_name=_("domain name"), blank=True, - help_text=_('Full domain name'), - max_length=255 + help_text=_("Full domain name"), + max_length=255, ) certificate_type = models.PositiveIntegerField( choices=CertificateType(), default=CertificateType.ov.id, ) certificate_repository = models.CharField( - verbose_name=_('certificate repository'), + verbose_name=_("certificate repository"), blank=True, - help_text=_('Certificate source repository'), - max_length=255 + help_text=_("Certificate source repository"), + max_length=255, ) issued_by = models.ForeignKey( Manufacturer, @@ -50,10 +50,10 @@ class SSLCertificate(AdminAbsoluteUrlMixin, PriceMixin, BaseObject): date_to = models.DateField(null=False, blank=False) san = models.TextField( blank=True, - help_text=_('All Subject Alternative Names'), + help_text=_("All Subject Alternative Names"), ) def __str__(self): - return '{} from {} to {}'.format( - self.name, self.date_from, self.date_to - ) or None + return ( + "{} from {} to {}".format(self.name, self.date_from, self.date_to) or None + ) diff --git a/src/ralph/ssl_certificates/tests/api.py b/src/ralph/ssl_certificates/tests/api.py index 87fa17b4a6..e127109950 100644 --- a/src/ralph/ssl_certificates/tests/api.py +++ b/src/ralph/ssl_certificates/tests/api.py @@ -14,36 +14,39 @@ def setUp(self): def test_get_certificates_list(self): url = reverse("sslcertificate-list") - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], SSLCertificate.objects.count()) + self.assertEqual(response.data["count"], SSLCertificate.objects.count()) def test_get_certificate_with_details(self): - url = reverse('sslcertificate-detail', args=(self.certificate1.id,)) - response = self.client.get(url, format='json') + url = reverse("sslcertificate-detail", args=(self.certificate1.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) for i in [ - "name", "domain_ssl", "date_from", "date_to", "san", - "price", "certificate_repository" + "name", + "domain_ssl", + "date_from", + "date_to", + "san", + "price", + "certificate_repository", ]: - self.assertEqual( - response.data[i], getattr(self.certificate1, i) - ) + self.assertEqual(response.data[i], getattr(self.certificate1, i)) def test_get_ssl_with_service_env(self): - url = reverse('sslcertificate-detail', args=(self.certificate1.id,)) - response = self.client.get(url, format='json') + url = reverse("sslcertificate-detail", args=(self.certificate1.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( - response.data['service_env']['id'], self.certificate1.service_env.id + response.data["service_env"]["id"], self.certificate1.service_env.id ) self.assertEqual( - response.data['service_env']['service'], - self.certificate1.service_env.service.name + response.data["service_env"]["service"], + self.certificate1.service_env.service.name, ) self.assertEqual( - response.data['service_env']['environment'], - self.certificate1.service_env.environment.name + response.data["service_env"]["environment"], + self.certificate1.service_env.environment.name, ) diff --git a/src/ralph/ssl_certificates/tests/factories.py b/src/ralph/ssl_certificates/tests/factories.py index ffcd318629..ded2278e77 100644 --- a/src/ralph/ssl_certificates/tests/factories.py +++ b/src/ralph/ssl_certificates/tests/factories.py @@ -1,24 +1,21 @@ -from datetime import date, datetime, timedelta +from datetime import datetime, timedelta import factory from factory.django import DjangoModelFactory -from ralph.assets.tests.factories import ( - ManufacturerFactory, - ServiceEnvironmentFactory -) +from ralph.assets.tests.factories import ManufacturerFactory, ServiceEnvironmentFactory from ralph.ssl_certificates.models import CertificateType, SSLCertificate date_now = datetime.now().date() class SSLCertificatesFactory(DjangoModelFactory): - name = factory.Sequence(lambda n: 'www.name{}.com'.format(n)) + name = factory.Sequence(lambda n: "www.name{}.com".format(n)) certificate_type = CertificateType.ov issued_by = factory.SubFactory(ManufacturerFactory) date_from = date_now - timedelta(days=15) date_to = date_now + timedelta(days=365) - san = factory.Faker('ssn') + san = factory.Faker("ssn") service_env = factory.SubFactory(ServiceEnvironmentFactory) class Meta: diff --git a/src/ralph/ssl_certificates/tests/tests.py b/src/ralph/ssl_certificates/tests/tests.py index 0c9b8b68cf..ca3cbcdcb5 100644 --- a/src/ralph/ssl_certificates/tests/tests.py +++ b/src/ralph/ssl_certificates/tests/tests.py @@ -11,69 +11,60 @@ class ImportSSLCertificatesTest(TestCase): def setUp(self): - self.base_dir = os.path.dirname( - os.path.dirname(__file__) - ) - self.samples_dir = os.path.join( - self.base_dir, 'tests', 'samples' - ) + self.base_dir = os.path.dirname(os.path.dirname(__file__)) + self.samples_dir = os.path.join(self.base_dir, "tests", "samples") def test_command_output(self): out = StringIO() - call_command('import_ssl_certificates', '404', stderr=out) - self.assertIn('', out.getvalue()) + call_command("import_ssl_certificates", "404", stderr=out) + self.assertIn("", out.getvalue()) def test_wildcard_certificate_domain_ssl_should_by_without_prefix(self): # noqa out = StringIO() - call_command('import_ssl_certificates', self.samples_dir, stderr=out) - self.assertTrue(SSLCertificate.objects.get(domain_ssl='lewitowanie.com.pl')) + call_command("import_ssl_certificates", self.samples_dir, stderr=out) + self.assertTrue(SSLCertificate.objects.get(domain_ssl="lewitowanie.com.pl")) def test_ssl_should_have_proper_type(self): out = StringIO() - call_command('import_ssl_certificates', self.samples_dir, stderr=out) - self.assertTrue(SSLCertificate.objects.get( - certificate_type=CertificateType.wildcard.id - )) + call_command("import_ssl_certificates", self.samples_dir, stderr=out) + self.assertTrue( + SSLCertificate.objects.get(certificate_type=CertificateType.wildcard.id) + ) def test_command_should_read_issuer(self): out = StringIO() - call_command('import_ssl_certificates', self.samples_dir, stderr=out) - expected = Manufacturer.objects.get( - name='My Company') + call_command("import_ssl_certificates", self.samples_dir, stderr=out) + expected = Manufacturer.objects.get(name="My Company") self.assertTrue(SSLCertificate.objects.get(issued_by=expected)) def test_command_should_read_san(self): out = StringIO() - call_command('import_ssl_certificates', self.samples_dir, stderr=out) - self.assertTrue( - SSLCertificate.objects.get( - san="['www.lewitowanie.com.pl']" - ) - ) + call_command("import_ssl_certificates", self.samples_dir, stderr=out) + self.assertTrue(SSLCertificate.objects.get(san="['www.lewitowanie.com.pl']")) def test_certificate_domain_name(self): out = StringIO() - call_command('import_ssl_certificates', self.samples_dir, stderr=out) - self.assertTrue( - SSLCertificate.objects.get( - name='wildcard_lewitowanie.com.pl' - ) - ) + call_command("import_ssl_certificates", self.samples_dir, stderr=out) + self.assertTrue(SSLCertificate.objects.get(name="wildcard_lewitowanie.com.pl")) def test_command_rise_break_certificate(self): out = StringIO() - call_command('import_ssl_certificates', self.samples_dir, stderr=out) + call_command("import_ssl_certificates", self.samples_dir, stderr=out) self.assertIn( - '{}/unproper/fake_ssl.crt is not valid\n'.format(self.samples_dir), - out.getvalue() + "{}/unproper/fake_ssl.crt is not valid\n".format(self.samples_dir), + out.getvalue(), ) class UpdateServiceEnvTest(TestCase): - @patch('ralph.dns.dnsaas.requests') - @patch('ralph.ssl_certificates.management.commands.update_dns_service_env_from_dnsaas.DNSaaS') - def test_command_should_informed_if_service_not_exist(self, dnsaas_client_class, requests): + @patch("ralph.dns.dnsaas.requests") + @patch( + "ralph.ssl_certificates.management.commands.update_dns_service_env_from_dnsaas.DNSaaS" + ) + def test_command_should_informed_if_service_not_exist( + self, dnsaas_client_class, requests + ): dnsaas_client = MagicMock() dnsaas_client_class.side_effect = lambda: dnsaas_client dnsaas_client.get_api_result.return_value = [ @@ -99,12 +90,13 @@ def test_command_should_informed_if_service_not_exist(self, dnsaas_client_class, "name": "tb-bw3.9.local", "content": "hhh.9.local", } - ] - } + ], + } requests.get.return_value = MagicMock(ok=True) requests.get.return_value.json.return_value = requests.get.return_value out = StringIO() - call_command('update_dns_service_env_from_dnsaas', stderr=out) + call_command("update_dns_service_env_from_dnsaas", stderr=out) self.assertIn( - 'Service with name Serwis porcelanowy and prod environment does not exist\n', out.getvalue() + "Service with name Serwis porcelanowy and prod environment does not exist\n", + out.getvalue(), ) diff --git a/src/ralph/supports/admin.py b/src/ralph/supports/admin.py index ad3d2fe14a..858455a6f5 100644 --- a/src/ralph/supports/admin.py +++ b/src/ralph/supports/admin.py @@ -8,11 +8,7 @@ from ralph.admin.decorators import register from ralph.admin.filters import TagsListFilter from ralph.admin.helpers import generate_html_link -from ralph.admin.mixins import ( - BulkEditChangeListMixin, - RalphAdmin, - RalphTabularInline -) +from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphTabularInline from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.attachments.admin import AttachmentsMixin from ralph.data_importer import resources @@ -22,18 +18,18 @@ class BaseObjectSupportView(RalphDetailViewAdmin): - icon = 'laptop' - name = 'base-object-assignments' - label = _('Assignments') - url_name = 'assignments' + icon = "laptop" + name = "base-object-assignments" + label = _("Assignments") + url_name = "assignments" class BaseObjectSupportInline(RalphTabularInline): model = BaseObjectsSupport - raw_id_fields = ('baseobject',) + raw_id_fields = ("baseobject",) extra = 1 - verbose_name = _('assignments') - verbose_name_plural = _('Assignments') - fk_name = 'support' + verbose_name = _("assignments") + verbose_name_plural = _("Assignments") + fk_name = "support" inlines = [BaseObjectSupportInline] @@ -42,79 +38,129 @@ class SupportAdminForm(PriceFormMixin, RalphAdmin.form): """ Service_env is not required for Supports. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # backward compatibility - service_env_field = self.fields.get('service_env', None) + service_env_field = self.fields.get("service_env", None) if service_env_field: service_env_field.required = False @register(Support) class SupportAdmin( - AttachmentsMixin, - CustomFieldValueAdminMixin, - BulkEditChangeListMixin, - RalphAdmin + AttachmentsMixin, CustomFieldValueAdminMixin, BulkEditChangeListMixin, RalphAdmin ): - """Support model admin class.""" change_views = [BaseObjectSupportView] - actions = ['bulk_edit_action'] + actions = ["bulk_edit_action"] form = SupportAdminForm - search_fields = [ - 'name', 'serial_no', 'contract_id', 'description', 'remarks' - ] + search_fields = ["name", "serial_no", "contract_id", "description", "remarks"] list_filter = [ - 'contract_id', 'name', 'serial_no', 'price', 'remarks', 'description', - 'support_type', 'budget_info', 'date_from', 'date_to', 'property_of', - TagsListFilter + "contract_id", + "name", + "serial_no", + "price", + "remarks", + "description", + "support_type", + "budget_info", + "date_from", + "date_to", + "property_of", + TagsListFilter, ] - date_hierarchy = 'created' + date_hierarchy = "created" list_display = [ - 'support_type', 'contract_id', 'name', 'serial_no', 'service_env', - 'date_from', 'date_to', 'created', 'remarks', 'description' + "support_type", + "contract_id", + "name", + "serial_no", + "service_env", + "date_from", + "date_to", + "created", + "remarks", + "description", ] bulk_edit_list = [ - 'status', 'asset_type', 'contract_id', 'description', 'price', - 'date_from', 'date_to', 'escalation_path', 'contract_terms', - 'sla_type', 'producer', 'supplier', 'serial_no', 'service_env', - 'invoice_no', 'invoice_date', 'period_in_months', 'property_of', - 'budget_info', 'support_type' + "status", + "asset_type", + "contract_id", + "description", + "price", + "date_from", + "date_to", + "escalation_path", + "contract_terms", + "sla_type", + "producer", + "supplier", + "serial_no", + "service_env", + "invoice_no", + "invoice_date", + "period_in_months", + "property_of", + "budget_info", + "support_type", ] list_select_related = [ - 'support_type', 'service_env', 'service_env__service', - 'service_env__environment' + "support_type", + "service_env", + "service_env__service", + "service_env__environment", ] resource_class = resources.SupportResource - raw_id_fields = ['budget_info', 'region', 'support_type', 'service_env'] + raw_id_fields = ["budget_info", "region", "support_type", "service_env"] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'support_type', 'name', 'status', 'producer', 'description', - 'date_from', 'date_to', 'serial_no', 'escalation_path', - 'region', 'remarks', 'service_env' - ) - }), - (_('Contract info'), { - 'fields': ( - 'contract_id', 'contract_terms', 'sla_type', 'price', - 'supplier', 'invoice_date', 'invoice_no', 'budget_info', - 'period_in_months', 'property_of', - ) - }), + ( + _("Basic info"), + { + "fields": ( + "support_type", + "name", + "status", + "producer", + "description", + "date_from", + "date_to", + "serial_no", + "escalation_path", + "region", + "remarks", + "service_env", + ) + }, + ), + ( + _("Contract info"), + { + "fields": ( + "contract_id", + "contract_terms", + "sla_type", + "price", + "supplier", + "invoice_date", + "invoice_no", + "budget_info", + "period_in_months", + "property_of", + ) + }, + ), ) - _export_queryset_manager = 'objects_with_related' + _export_queryset_manager = "objects_with_related" @register(SupportType) class SupportTypeAdmin(RalphAdmin): - resource_class = resources.SupportTypeResource - search_fields = ['name'] + search_fields = ["name"] @register(BaseObjectsSupport) @@ -122,33 +168,44 @@ class BaseObjectsSupportAdmin(RalphAdmin): redirect_to_detail_view_if_one_search_result = False resource_class = resources.BaseObjectsSupportRichResource search_fields = [ - 'support__name', 'support__serial_no', 'support__contract_id', - 'support__description', 'support__remarks', + "support__name", + "support__serial_no", + "support__contract_id", + "support__description", + "support__remarks", ] list_filter = [ - 'support__contract_id', 'support__name', 'support__serial_no', - 'support__price', 'support__support_type', 'support__budget_info', - 'support__date_from', 'support__date_to', 'support__property_of', - 'baseobject__asset__barcode', 'baseobject__asset__sn', - 'baseobject__asset__hostname', 'baseobject__asset__service_env', + "support__contract_id", + "support__name", + "support__serial_no", + "support__price", + "support__support_type", + "support__budget_info", + "support__date_from", + "support__date_to", + "support__property_of", + "baseobject__asset__barcode", + "baseobject__asset__sn", + "baseobject__asset__hostname", + "baseobject__asset__service_env", ] list_display = [ - '_get_support_type', - '_get_support_contract_id', - '_get_support_name', - '_get_support_price', - '_get_support_date_from', - '_get_support_date_to', - '_get_asset_hostname', - '_get_asset_service_env', + "_get_support_type", + "_get_support_contract_id", + "_get_support_name", + "_get_support_price", + "_get_support_date_from", + "_get_support_date_to", + "_get_asset_hostname", + "_get_asset_service_env", ] - raw_id_fields = ['support', 'baseobject'] + raw_id_fields = ["support", "baseobject"] list_select_related = [ - 'support', - 'support__support_type', - 'baseobject__asset', - 'baseobject__service_env__service', - 'baseobject__service_env__environment', + "support", + "support__support_type", + "baseobject__asset", + "baseobject__service_env__service", + "baseobject__service_env__environment", ] list_display_links = None @@ -156,17 +213,21 @@ class BaseObjectsSupportAdmin(RalphAdmin): def get_queryset(self, request): # fetch additional objects_count for exporter - return super().get_queryset(request).annotate( - objects_count=Count('support__baseobjectssupport') + return ( + super() + .get_queryset(request) + .annotate(objects_count=Count("support__baseobjectssupport")) ) # disable edit view, adding and deleting objects from here def change_view(self, request, obj=None): opts = self.model._meta - url = reverse('admin:{app}_{model}_changelist'.format( - app=opts.app_label, - model=opts.model_name, - )) + url = reverse( + "admin:{app}_{model}_changelist".format( + app=opts.app_label, + model=opts.model_name, + ) + ) return HttpResponseRedirect(url) def has_add_permission(self, request): @@ -184,33 +245,39 @@ def _get_support_type(self, obj): label=obj.support.support_type, params={}, ) - _get_support_type.short_description = _('support type') - _get_support_type.admin_order_field = 'support__support_type' + + _get_support_type.short_description = _("support type") + _get_support_type.admin_order_field = "support__support_type" def _get_support_contract_id(self, obj): return obj.support.contract_id - _get_support_contract_id.short_description = _('support contract id') - _get_support_contract_id.admin_order_field = 'support__contract_id' + + _get_support_contract_id.short_description = _("support contract id") + _get_support_contract_id.admin_order_field = "support__contract_id" def _get_support_name(self, obj): return obj.support.contract_id - _get_support_name.short_description = _('support name') - _get_support_name.admin_order_field = 'support__name' + + _get_support_name.short_description = _("support name") + _get_support_name.admin_order_field = "support__name" def _get_support_price(self, obj): return obj.support.price - _get_support_price.short_description = _('support price') - _get_support_price.admin_order_field = 'support__price' + + _get_support_price.short_description = _("support price") + _get_support_price.admin_order_field = "support__price" def _get_support_date_from(self, obj): return obj.support.date_from - _get_support_date_from.short_description = _('support date from') - _get_support_date_from.admin_order_field = 'support__date_from' + + _get_support_date_from.short_description = _("support date from") + _get_support_date_from.admin_order_field = "support__date_from" def _get_support_date_to(self, obj): return obj.support.date_to - _get_support_date_to.short_description = _('support date to') - _get_support_date_to.admin_order_field = 'support__date_to' + + _get_support_date_to.short_description = _("support date to") + _get_support_date_to.admin_order_field = "support__date_to" @mark_safe def _get_asset_hostname(self, obj): @@ -219,10 +286,12 @@ def _get_asset_hostname(self, obj): label=obj.baseobject.asset.hostname, params={}, ) - _get_asset_hostname.short_description = _('asset hostname') - _get_asset_hostname.admin_order_field = 'baseobject__asset__hostname' + + _get_asset_hostname.short_description = _("asset hostname") + _get_asset_hostname.admin_order_field = "baseobject__asset__hostname" def _get_asset_service_env(self, obj): return obj.baseobject.service_env - _get_asset_service_env.short_description = _('asset service env') - _get_asset_service_env.admin_order_field = 'baseobject__service_env__service__name' # noqa + + _get_asset_service_env.short_description = _("asset service env") + _get_asset_service_env.admin_order_field = "baseobject__service_env__service__name" # noqa diff --git a/src/ralph/supports/api.py b/src/ralph/supports/api.py index 6576f03bcd..3c091980ca 100644 --- a/src/ralph/supports/api.py +++ b/src/ralph/supports/api.py @@ -6,7 +6,7 @@ from ralph.assets.api.serializers import ( ServiceEnvironmentSimpleSerializer, StrField, - TypeFromContentTypeSerializerMixin + TypeFromContentTypeSerializerMixin, ) from ralph.assets.models import BaseObject from ralph.supports.models import BaseObjectsSupport, Support, SupportType @@ -27,8 +27,16 @@ class SupportSimpleSerializer(RalphAPISerializer): class Meta: model = Support fields = [ - 'support_type', 'contract_id', 'name', 'serial_no', 'date_from', - 'date_to', 'created', 'remarks', 'description', 'url' + "support_type", + "contract_id", + "name", + "serial_no", + "date_from", + "date_to", + "created", + "remarks", + "description", + "url", ] _skip_tags_field = True @@ -36,32 +44,38 @@ class Meta: class SupportSerializer(TypeFromContentTypeSerializerMixin, RalphAPISerializer): __str__ = StrField(show_type=True) base_objects = serializers.HyperlinkedRelatedField( - many=True, view_name='baseobject-detail', read_only=True + many=True, view_name="baseobject-detail", read_only=True ) service_env = ServiceEnvironmentSimpleSerializer() class Meta: model = Support depth = 1 - exclude = ('content_type', 'configuration_path') + exclude = ("content_type", "configuration_path") class SupportViewSet(RalphAPIViewSet): queryset = Support.objects.all() serializer_class = SupportSerializer select_related = [ - 'region', 'budget_info', 'support_type', 'property_of', 'service_env', - 'service_env__service', 'service_env__environment' + "region", + "budget_info", + "support_type", + "property_of", + "service_env", + "service_env__service", + "service_env__environment", + ] + prefetch_related = [ + "tags", + Prefetch("base_objects", queryset=BaseObject.objects.all()), ] - prefetch_related = ['tags', Prefetch( - 'base_objects', queryset=BaseObject.objects.all() - )] class BaseObjectsSupportSerializer(RalphAPISerializer): support = SupportSimpleSerializer() baseobject = serializers.HyperlinkedRelatedField( - view_name='baseobject-detail', read_only=True + view_name="baseobject-detail", read_only=True ) class Meta: @@ -72,10 +86,10 @@ class Meta: class BaseObjectSupportViewSet(RalphAPIViewSet): queryset = BaseObjectsSupport.objects.all() serializer_class = BaseObjectsSupportSerializer - select_related = ['baseobject', 'support'] + select_related = ["baseobject", "support"] -router.register(r'base-objects-supports', BaseObjectSupportViewSet) -router.register(r'supports', SupportViewSet) -router.register(r'support-types', SupportTypeViewSet) +router.register(r"base-objects-supports", BaseObjectSupportViewSet) +router.register(r"supports", SupportViewSet) +router.register(r"support-types", SupportTypeViewSet) urlpatterns = [] diff --git a/src/ralph/supports/migrations/0001_initial.py b/src/ralph/supports/migrations/0001_initial.py index 89f75b4fdb..caf1847dd6 100644 --- a/src/ralph/supports/migrations/0001_initial.py +++ b/src/ralph/supports/migrations/0001_initial.py @@ -7,57 +7,148 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0001_initial'), - ('accounts', '0001_initial'), + ("assets", "0001_initial"), + ("accounts", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Support', + name="Support", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(verbose_name='name', max_length=75)), - ('asset_type', models.PositiveSmallIntegerField(choices=[(1, 'back office'), (2, 'data center'), (3, 'part'), (4, 'all')], default=4)), - ('contract_id', models.CharField(max_length=50)), - ('description', models.CharField(blank=True, max_length=100)), - ('price', models.DecimalField(blank=True, default=0, null=True, decimal_places=2, max_digits=10)), - ('date_from', models.DateField(blank=True, null=True)), - ('date_to', models.DateField()), - ('escalation_path', models.CharField(blank=True, max_length=200)), - ('contract_terms', models.TextField(blank=True)), - ('sla_type', models.CharField(blank=True, max_length=200)), - ('status', models.PositiveSmallIntegerField(verbose_name='status', choices=[(1, 'new')], default=1)), - ('producer', models.CharField(blank=True, max_length=100)), - ('supplier', models.CharField(blank=True, max_length=100)), - ('serial_no', models.CharField(blank=True, max_length=100)), - ('invoice_no', models.CharField(blank=True, db_index=True, max_length=100)), - ('invoice_date', models.DateField(verbose_name='Invoice date', blank=True, null=True)), - ('period_in_months', models.IntegerField(blank=True, null=True)), - ('base_objects', models.ManyToManyField(to='assets.BaseObject', related_name='supports')), - ('budget_info', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, default=None, to='assets.BudgetInfo', blank=True, null=True)), - ('property_of', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.AssetHolder', blank=True, null=True)), - ('region', models.ForeignKey(to='accounts.Region', on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("name", models.CharField(verbose_name="name", max_length=75)), + ( + "asset_type", + models.PositiveSmallIntegerField( + choices=[ + (1, "back office"), + (2, "data center"), + (3, "part"), + (4, "all"), + ], + default=4, + ), + ), + ("contract_id", models.CharField(max_length=50)), + ("description", models.CharField(blank=True, max_length=100)), + ( + "price", + models.DecimalField( + blank=True, + default=0, + null=True, + decimal_places=2, + max_digits=10, + ), + ), + ("date_from", models.DateField(blank=True, null=True)), + ("date_to", models.DateField()), + ("escalation_path", models.CharField(blank=True, max_length=200)), + ("contract_terms", models.TextField(blank=True)), + ("sla_type", models.CharField(blank=True, max_length=200)), + ( + "status", + models.PositiveSmallIntegerField( + verbose_name="status", choices=[(1, "new")], default=1 + ), + ), + ("producer", models.CharField(blank=True, max_length=100)), + ("supplier", models.CharField(blank=True, max_length=100)), + ("serial_no", models.CharField(blank=True, max_length=100)), + ( + "invoice_no", + models.CharField(blank=True, db_index=True, max_length=100), + ), + ( + "invoice_date", + models.DateField( + verbose_name="Invoice date", blank=True, null=True + ), + ), + ("period_in_months", models.IntegerField(blank=True, null=True)), + ( + "base_objects", + models.ManyToManyField( + to="assets.BaseObject", related_name="supports" + ), + ), + ( + "budget_info", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + default=None, + to="assets.BudgetInfo", + blank=True, + null=True, + ), + ), + ( + "property_of", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="assets.AssetHolder", + blank=True, + null=True, + ), + ), + ( + "region", + models.ForeignKey( + to="accounts.Region", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject', models.Model), + bases=( + ralph.lib.mixins.models.AdminAbsoluteUrlMixin, + "assets.baseobject", + models.Model, + ), ), migrations.CreateModel( - name='SupportType', + name="SupportType", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(verbose_name='name', unique=True, max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", unique=True, max_length=255), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.AddField( - model_name='support', - name='support_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, default=None, to='supports.SupportType', blank=True, null=True), + model_name="support", + name="support_type", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + default=None, + to="supports.SupportType", + blank=True, + null=True, + ), ), ] diff --git a/src/ralph/supports/migrations/0002_auto_20151204_0758.py b/src/ralph/supports/migrations/0002_auto_20151204_0758.py index a50f0d4bad..4fc1e04281 100644 --- a/src/ralph/supports/migrations/0002_auto_20151204_0758.py +++ b/src/ralph/supports/migrations/0002_auto_20151204_0758.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('supports', '0001_initial'), + ("supports", "0001_initial"), ] operations = [ migrations.AlterModelOptions( - name='supporttype', - options={'ordering': ['name']}, + name="supporttype", + options={"ordering": ["name"]}, ), ] diff --git a/src/ralph/supports/migrations/0003_auto_20151204_1325.py b/src/ralph/supports/migrations/0003_auto_20151204_1325.py index 74ef27e8bc..c610bed1f6 100644 --- a/src/ralph/supports/migrations/0003_auto_20151204_1325.py +++ b/src/ralph/supports/migrations/0003_auto_20151204_1325.py @@ -5,30 +5,41 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0002_auto_20151204_0758'), + ("supports", "0002_auto_20151204_0758"), ] operations = [ migrations.CreateModel( - name='BaseObjectsSupport', + name="BaseObjectsSupport", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), ], options={ - 'db_table': 'supports_support_base_objects', - 'managed': False, + "db_table": "supports_support_base_objects", + "managed": False, }, ), migrations.SeparateDatabaseAndState( state_operations=[ migrations.AlterField( - model_name='support', - name='base_objects', - field=models.ManyToManyField(related_name='supports', to='assets.BaseObject', through='supports.BaseObjectsSupport'), + model_name="support", + name="base_objects", + field=models.ManyToManyField( + related_name="supports", + to="assets.BaseObject", + through="supports.BaseObjectsSupport", + ), ), ], - database_operations=[] + database_operations=[], ), ] diff --git a/src/ralph/supports/migrations/0004_auto_20151229_0925.py b/src/ralph/supports/migrations/0004_auto_20151229_0925.py index 944d05280c..6169f344ce 100644 --- a/src/ralph/supports/migrations/0004_auto_20151229_0925.py +++ b/src/ralph/supports/migrations/0004_auto_20151229_0925.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('supports', '0003_auto_20151204_1325'), + ("supports", "0003_auto_20151204_1325"), ] operations = [ migrations.AlterUniqueTogether( - name='BaseObjectsSupport', - unique_together=set([('support', 'baseobject')]), + name="BaseObjectsSupport", + unique_together=set([("support", "baseobject")]), ), ] diff --git a/src/ralph/supports/migrations/0005_auto_20160105_1222.py b/src/ralph/supports/migrations/0005_auto_20160105_1222.py index 3142633bb3..efbb7356db 100644 --- a/src/ralph/supports/migrations/0005_auto_20160105_1222.py +++ b/src/ralph/supports/migrations/0005_auto_20160105_1222.py @@ -5,15 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0004_auto_20151229_0925'), + ("supports", "0004_auto_20151229_0925"), ] operations = [ migrations.AlterField( - model_name='support', - name='base_objects', - field=models.ManyToManyField(to='assets.BaseObject', through='supports.BaseObjectsSupport', related_name='_support_base_objects_+'), + model_name="support", + name="base_objects", + field=models.ManyToManyField( + to="assets.BaseObject", + through="supports.BaseObjectsSupport", + related_name="_support_base_objects_+", + ), ), ] diff --git a/src/ralph/supports/migrations/0006_auto_20160615_0805.py b/src/ralph/supports/migrations/0006_auto_20160615_0805.py index 91cdc5ce1c..0c93938f17 100644 --- a/src/ralph/supports/migrations/0006_auto_20160615_0805.py +++ b/src/ralph/supports/migrations/0006_auto_20160615_0805.py @@ -7,35 +7,44 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0005_auto_20160105_1222'), + ("supports", "0005_auto_20160105_1222"), ] operations = [ migrations.AlterModelOptions( - name='baseobjectssupport', + name="baseobjectssupport", options={}, ), migrations.AlterModelTable( - name='baseobjectssupport', + name="baseobjectssupport", table=None, ), migrations.SeparateDatabaseAndState( state_operations=[ migrations.AddField( - model_name='baseobjectssupport', - name='baseobject', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(default=0, verbose_name='Asset', to='assets.BaseObject', related_name='supports', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectssupport", + name="baseobject", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + default=0, + verbose_name="Asset", + to="assets.BaseObject", + related_name="supports", + on_delete=django.db.models.deletion.CASCADE, + ), preserve_default=False, ), migrations.AddField( - model_name='baseobjectssupport', - name='support', - field=models.ForeignKey(default=0, to='supports.Support', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectssupport", + name="support", + field=models.ForeignKey( + default=0, + to="supports.Support", + on_delete=django.db.models.deletion.CASCADE, + ), preserve_default=False, ), ], - database_operations=[] + database_operations=[], ), ] diff --git a/src/ralph/supports/migrations/0007_auto_20160823_0921.py b/src/ralph/supports/migrations/0007_auto_20160823_0921.py index 1c6a6c5edd..ca2dec8e6c 100644 --- a/src/ralph/supports/migrations/0007_auto_20160823_0921.py +++ b/src/ralph/supports/migrations/0007_auto_20160823_0921.py @@ -5,30 +5,33 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0006_auto_20160615_0805'), + ("supports", "0006_auto_20160615_0805"), ] operations = [ migrations.AlterField( - model_name='support', - name='contract_id', - field=models.CharField(max_length=50, verbose_name='contract ID'), + model_name="support", + name="contract_id", + field=models.CharField(max_length=50, verbose_name="contract ID"), ), migrations.AlterField( - model_name='support', - name='invoice_date', - field=models.DateField(null=True, blank=True, verbose_name='invoice date'), + model_name="support", + name="invoice_date", + field=models.DateField(null=True, blank=True, verbose_name="invoice date"), ), migrations.AlterField( - model_name='support', - name='invoice_no', - field=models.CharField(blank=True, verbose_name='invoice number', max_length=100, db_index=True), + model_name="support", + name="invoice_no", + field=models.CharField( + blank=True, verbose_name="invoice number", max_length=100, db_index=True + ), ), migrations.AlterField( - model_name='support', - name='serial_no', - field=models.CharField(blank=True, max_length=100, verbose_name='serial number'), + model_name="support", + name="serial_no", + field=models.CharField( + blank=True, max_length=100, verbose_name="serial number" + ), ), ] diff --git a/src/ralph/supports/migrations/0008_auto_20200909_1012.py b/src/ralph/supports/migrations/0008_auto_20200909_1012.py index d37ea21879..fadf3922ba 100644 --- a/src/ralph/supports/migrations/0008_auto_20200909_1012.py +++ b/src/ralph/supports/migrations/0008_auto_20200909_1012.py @@ -1,26 +1,227 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import djmoney.models.fields from decimal import Decimal class Migration(migrations.Migration): - dependencies = [ - ('supports', '0007_auto_20160823_0921'), + ("supports", "0007_auto_20160823_0921"), ] operations = [ migrations.AddField( - model_name='support', - name='price_currency', - field=djmoney.models.fields.CurrencyField(max_length=3, default='XXX', editable=False, choices=[('XXX', '---'), ('AED', 'AED'), ('AFN', 'AFN'), ('ALL', 'ALL'), ('AMD', 'AMD'), ('ANG', 'ANG'), ('AOA', 'AOA'), ('ARS', 'ARS'), ('AUD', 'AUD'), ('AWG', 'AWG'), ('AZN', 'AZN'), ('BAM', 'BAM'), ('BBD', 'BBD'), ('BDT', 'BDT'), ('BGN', 'BGN'), ('BHD', 'BHD'), ('BIF', 'BIF'), ('BMD', 'BMD'), ('BND', 'BND'), ('BOB', 'BOB'), ('BOV', 'BOV'), ('BRL', 'BRL'), ('BSD', 'BSD'), ('BTN', 'BTN'), ('BWP', 'BWP'), ('BYN', 'BYN'), ('BYR', 'BYR'), ('BZD', 'BZD'), ('CAD', 'CAD'), ('CDF', 'CDF'), ('CHE', 'CHE'), ('CHF', 'CHF'), ('CHW', 'CHW'), ('CLF', 'CLF'), ('CLP', 'CLP'), ('CNY', 'CNY'), ('COP', 'COP'), ('COU', 'COU'), ('CRC', 'CRC'), ('CUC', 'CUC'), ('CUP', 'CUP'), ('CVE', 'CVE'), ('CZK', 'CZK'), ('DJF', 'DJF'), ('DKK', 'DKK'), ('DOP', 'DOP'), ('DZD', 'DZD'), ('EGP', 'EGP'), ('ERN', 'ERN'), ('ETB', 'ETB'), ('EUR', 'EUR'), ('FJD', 'FJD'), ('FKP', 'FKP'), ('GBP', 'GBP'), ('GEL', 'GEL'), ('GHS', 'GHS'), ('GIP', 'GIP'), ('GMD', 'GMD'), ('GNF', 'GNF'), ('GTQ', 'GTQ'), ('GYD', 'GYD'), ('HKD', 'HKD'), ('HNL', 'HNL'), ('HRK', 'HRK'), ('HTG', 'HTG'), ('HUF', 'HUF'), ('IDR', 'IDR'), ('ILS', 'ILS'), ('IMP', 'IMP'), ('INR', 'INR'), ('IQD', 'IQD'), ('IRR', 'IRR'), ('ISK', 'ISK'), ('JMD', 'JMD'), ('JOD', 'JOD'), ('JPY', 'JPY'), ('KES', 'KES'), ('KGS', 'KGS'), ('KHR', 'KHR'), ('KMF', 'KMF'), ('KPW', 'KPW'), ('KRW', 'KRW'), ('KWD', 'KWD'), ('KYD', 'KYD'), ('KZT', 'KZT'), ('LAK', 'LAK'), ('LBP', 'LBP'), ('LKR', 'LKR'), ('LRD', 'LRD'), ('LSL', 'LSL'), ('LTL', 'LTL'), ('LVL', 'LVL'), ('LYD', 'LYD'), ('MAD', 'MAD'), ('MDL', 'MDL'), ('MGA', 'MGA'), ('MKD', 'MKD'), ('MMK', 'MMK'), ('MNT', 'MNT'), ('MOP', 'MOP'), ('MRO', 'MRO'), ('MUR', 'MUR'), ('MVR', 'MVR'), ('MWK', 'MWK'), ('MXN', 'MXN'), ('MXV', 'MXV'), ('MYR', 'MYR'), ('MZN', 'MZN'), ('NAD', 'NAD'), ('NGN', 'NGN'), ('NIO', 'NIO'), ('NOK', 'NOK'), ('NPR', 'NPR'), ('NZD', 'NZD'), ('OMR', 'OMR'), ('PAB', 'PAB'), ('PEN', 'PEN'), ('PGK', 'PGK'), ('PHP', 'PHP'), ('PKR', 'PKR'), ('PLN', 'PLN'), ('PYG', 'PYG'), ('QAR', 'QAR'), ('RON', 'RON'), ('RSD', 'RSD'), ('RUB', 'RUB'), ('RWF', 'RWF'), ('SAR', 'SAR'), ('SBD', 'SBD'), ('SCR', 'SCR'), ('SDG', 'SDG'), ('SEK', 'SEK'), ('SGD', 'SGD'), ('SHP', 'SHP'), ('SLL', 'SLL'), ('SOS', 'SOS'), ('SRD', 'SRD'), ('SSP', 'SSP'), ('STD', 'STD'), ('SVC', 'SVC'), ('SYP', 'SYP'), ('SZL', 'SZL'), ('THB', 'THB'), ('TJS', 'TJS'), ('TMM', 'TMM'), ('TMT', 'TMT'), ('TND', 'TND'), ('TOP', 'TOP'), ('TRY', 'TRY'), ('TTD', 'TTD'), ('TVD', 'TVD'), ('TWD', 'TWD'), ('TZS', 'TZS'), ('UAH', 'UAH'), ('UGX', 'UGX'), ('USD', 'USD'), ('USN', 'USN'), ('UYI', 'UYI'), ('UYU', 'UYU'), ('UZS', 'UZS'), ('VEF', 'VEF'), ('VND', 'VND'), ('VUV', 'VUV'), ('WST', 'WST'), ('XAF', 'XAF'), ('XAG', 'XAG'), ('XAU', 'XAU'), ('XBA', 'XBA'), ('XBB', 'XBB'), ('XBC', 'XBC'), ('XBD', 'XBD'), ('XCD', 'XCD'), ('XDR', 'XDR'), ('XFO', 'XFO'), ('XFU', 'XFU'), ('XOF', 'XOF'), ('XPD', 'XPD'), ('XPF', 'XPF'), ('XPT', 'XPT'), ('XSU', 'XSU'), ('XTS', 'XTS'), ('XUA', 'XUA'), ('XYZ', 'XYZ'), ('YER', 'YER'), ('ZAR', 'ZAR'), ('ZMK', 'ZMK'), ('ZMW', 'ZMW'), ('ZWD', 'ZWD'), ('ZWL', 'ZWL'), ('ZWN', 'ZWN')]), + model_name="support", + name="price_currency", + field=djmoney.models.fields.CurrencyField( + max_length=3, + default="XXX", + editable=False, + choices=[ + ("XXX", "---"), + ("AED", "AED"), + ("AFN", "AFN"), + ("ALL", "ALL"), + ("AMD", "AMD"), + ("ANG", "ANG"), + ("AOA", "AOA"), + ("ARS", "ARS"), + ("AUD", "AUD"), + ("AWG", "AWG"), + ("AZN", "AZN"), + ("BAM", "BAM"), + ("BBD", "BBD"), + ("BDT", "BDT"), + ("BGN", "BGN"), + ("BHD", "BHD"), + ("BIF", "BIF"), + ("BMD", "BMD"), + ("BND", "BND"), + ("BOB", "BOB"), + ("BOV", "BOV"), + ("BRL", "BRL"), + ("BSD", "BSD"), + ("BTN", "BTN"), + ("BWP", "BWP"), + ("BYN", "BYN"), + ("BYR", "BYR"), + ("BZD", "BZD"), + ("CAD", "CAD"), + ("CDF", "CDF"), + ("CHE", "CHE"), + ("CHF", "CHF"), + ("CHW", "CHW"), + ("CLF", "CLF"), + ("CLP", "CLP"), + ("CNY", "CNY"), + ("COP", "COP"), + ("COU", "COU"), + ("CRC", "CRC"), + ("CUC", "CUC"), + ("CUP", "CUP"), + ("CVE", "CVE"), + ("CZK", "CZK"), + ("DJF", "DJF"), + ("DKK", "DKK"), + ("DOP", "DOP"), + ("DZD", "DZD"), + ("EGP", "EGP"), + ("ERN", "ERN"), + ("ETB", "ETB"), + ("EUR", "EUR"), + ("FJD", "FJD"), + ("FKP", "FKP"), + ("GBP", "GBP"), + ("GEL", "GEL"), + ("GHS", "GHS"), + ("GIP", "GIP"), + ("GMD", "GMD"), + ("GNF", "GNF"), + ("GTQ", "GTQ"), + ("GYD", "GYD"), + ("HKD", "HKD"), + ("HNL", "HNL"), + ("HRK", "HRK"), + ("HTG", "HTG"), + ("HUF", "HUF"), + ("IDR", "IDR"), + ("ILS", "ILS"), + ("IMP", "IMP"), + ("INR", "INR"), + ("IQD", "IQD"), + ("IRR", "IRR"), + ("ISK", "ISK"), + ("JMD", "JMD"), + ("JOD", "JOD"), + ("JPY", "JPY"), + ("KES", "KES"), + ("KGS", "KGS"), + ("KHR", "KHR"), + ("KMF", "KMF"), + ("KPW", "KPW"), + ("KRW", "KRW"), + ("KWD", "KWD"), + ("KYD", "KYD"), + ("KZT", "KZT"), + ("LAK", "LAK"), + ("LBP", "LBP"), + ("LKR", "LKR"), + ("LRD", "LRD"), + ("LSL", "LSL"), + ("LTL", "LTL"), + ("LVL", "LVL"), + ("LYD", "LYD"), + ("MAD", "MAD"), + ("MDL", "MDL"), + ("MGA", "MGA"), + ("MKD", "MKD"), + ("MMK", "MMK"), + ("MNT", "MNT"), + ("MOP", "MOP"), + ("MRO", "MRO"), + ("MUR", "MUR"), + ("MVR", "MVR"), + ("MWK", "MWK"), + ("MXN", "MXN"), + ("MXV", "MXV"), + ("MYR", "MYR"), + ("MZN", "MZN"), + ("NAD", "NAD"), + ("NGN", "NGN"), + ("NIO", "NIO"), + ("NOK", "NOK"), + ("NPR", "NPR"), + ("NZD", "NZD"), + ("OMR", "OMR"), + ("PAB", "PAB"), + ("PEN", "PEN"), + ("PGK", "PGK"), + ("PHP", "PHP"), + ("PKR", "PKR"), + ("PLN", "PLN"), + ("PYG", "PYG"), + ("QAR", "QAR"), + ("RON", "RON"), + ("RSD", "RSD"), + ("RUB", "RUB"), + ("RWF", "RWF"), + ("SAR", "SAR"), + ("SBD", "SBD"), + ("SCR", "SCR"), + ("SDG", "SDG"), + ("SEK", "SEK"), + ("SGD", "SGD"), + ("SHP", "SHP"), + ("SLL", "SLL"), + ("SOS", "SOS"), + ("SRD", "SRD"), + ("SSP", "SSP"), + ("STD", "STD"), + ("SVC", "SVC"), + ("SYP", "SYP"), + ("SZL", "SZL"), + ("THB", "THB"), + ("TJS", "TJS"), + ("TMM", "TMM"), + ("TMT", "TMT"), + ("TND", "TND"), + ("TOP", "TOP"), + ("TRY", "TRY"), + ("TTD", "TTD"), + ("TVD", "TVD"), + ("TWD", "TWD"), + ("TZS", "TZS"), + ("UAH", "UAH"), + ("UGX", "UGX"), + ("USD", "USD"), + ("USN", "USN"), + ("UYI", "UYI"), + ("UYU", "UYU"), + ("UZS", "UZS"), + ("VEF", "VEF"), + ("VND", "VND"), + ("VUV", "VUV"), + ("WST", "WST"), + ("XAF", "XAF"), + ("XAG", "XAG"), + ("XAU", "XAU"), + ("XBA", "XBA"), + ("XBB", "XBB"), + ("XBC", "XBC"), + ("XBD", "XBD"), + ("XCD", "XCD"), + ("XDR", "XDR"), + ("XFO", "XFO"), + ("XFU", "XFU"), + ("XOF", "XOF"), + ("XPD", "XPD"), + ("XPF", "XPF"), + ("XPT", "XPT"), + ("XSU", "XSU"), + ("XTS", "XTS"), + ("XUA", "XUA"), + ("XYZ", "XYZ"), + ("YER", "YER"), + ("ZAR", "ZAR"), + ("ZMK", "ZMK"), + ("ZMW", "ZMW"), + ("ZWD", "ZWD"), + ("ZWL", "ZWL"), + ("ZWN", "ZWN"), + ], + ), ), migrations.AlterField( - model_name='support', - name='price', - field=djmoney.models.fields.MoneyField(null=True, default=Decimal('0'), max_digits=15, decimal_places=2, default_currency='XXX'), + model_name="support", + name="price", + field=djmoney.models.fields.MoneyField( + null=True, + default=Decimal("0"), + max_digits=15, + decimal_places=2, + default_currency="XXX", + ), ), ] diff --git a/src/ralph/supports/migrations/0009_auto_20240506_1633.py b/src/ralph/supports/migrations/0009_auto_20240506_1633.py index 853f53829b..91128bc731 100644 --- a/src/ralph/supports/migrations/0009_auto_20240506_1633.py +++ b/src/ralph/supports/migrations/0009_auto_20240506_1633.py @@ -7,16 +7,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0008_auto_20200909_1012'), + ("supports", "0008_auto_20200909_1012"), ] operations = [ migrations.AlterModelManagers( - name='support', + name="support", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/supports/migrations/0010_auto_20240628_1207.py b/src/ralph/supports/migrations/0010_auto_20240628_1207.py index 48d016a270..b8cd1f31be 100644 --- a/src/ralph/supports/migrations/0010_auto_20240628_1207.py +++ b/src/ralph/supports/migrations/0010_auto_20240628_1207.py @@ -6,15 +6,23 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0009_auto_20240506_1633'), + ("supports", "0009_auto_20240506_1633"), ] operations = [ migrations.AlterField( - model_name='baseobjectssupport', - name='baseobject', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_models=['back_office.BackOfficeAsset', 'data_center.DataCenterAsset'], on_delete=django.db.models.deletion.CASCADE, related_name='supports', to='assets.BaseObject', verbose_name='Asset'), + model_name="baseobjectssupport", + name="baseobject", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_models=[ + "back_office.BackOfficeAsset", + "data_center.DataCenterAsset", + ], + on_delete=django.db.models.deletion.CASCADE, + related_name="supports", + to="assets.BaseObject", + verbose_name="Asset", + ), ), ] diff --git a/src/ralph/supports/migrations/0010_auto_20241002_1122.py b/src/ralph/supports/migrations/0010_auto_20241002_1122.py index e2361d3907..e039e824d9 100644 --- a/src/ralph/supports/migrations/0010_auto_20241002_1122.py +++ b/src/ralph/supports/migrations/0010_auto_20241002_1122.py @@ -7,15 +7,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0009_auto_20240506_1633'), + ("supports", "0009_auto_20240506_1633"), ] operations = [ migrations.AlterField( - model_name='support', - name='base_objects', - field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField(related_name='_support_base_objects_+', through='supports.BaseObjectsSupport', to='assets.BaseObject'), + model_name="support", + name="base_objects", + field=ralph.lib.polymorphic.fields.PolymorphicManyToManyField( + related_name="_support_base_objects_+", + through="supports.BaseObjectsSupport", + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/supports/migrations/0011_merge_20241008_1131.py b/src/ralph/supports/migrations/0011_merge_20241008_1131.py index f0f85c6772..9266cf74a4 100644 --- a/src/ralph/supports/migrations/0011_merge_20241008_1131.py +++ b/src/ralph/supports/migrations/0011_merge_20241008_1131.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('supports', '0010_auto_20240628_1207'), - ('supports', '0010_auto_20241002_1122'), + ("supports", "0010_auto_20240628_1207"), + ("supports", "0010_auto_20241002_1122"), ] - operations = [ - ] + operations = [] diff --git a/src/ralph/supports/models.py b/src/ralph/supports/models.py index db25377317..6963ff4741 100644 --- a/src/ralph/supports/models.py +++ b/src/ralph/supports/models.py @@ -12,11 +12,7 @@ from ralph.assets.models.base import BaseObject from ralph.assets.models.choices import ObjectModelType from ralph.lib.mixins.fields import BaseObjectForeignKey -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - PriceMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, PriceMixin from ralph.lib.polymorphic.fields import PolymorphicManyToManyField from ralph.lib.polymorphic.models import PolymorphicQuerySet @@ -37,18 +33,20 @@ class SupportStatus(Choices): # [bos.base_object for bos in support.baseobjectssupport_set.all()] # without additional queries models.Prefetch( - 'baseobjectssupport_set__baseobject', + "baseobjectssupport_set__baseobject", # polymorphic manager is used to get final instance of the object # (ex. DataCenterAsset) - queryset=BaseObject.polymorphic_objects.all() + queryset=BaseObject.polymorphic_objects.all(), ) ] class AssignedObjectsCountManager(models.Manager): def get_queryset(self): - return super().get_queryset().annotate( - assigned_objects_count=models.Count('base_objects') + return ( + super() + .get_queryset() + .annotate(assigned_objects_count=models.Count("base_objects")) ) @@ -56,9 +54,12 @@ class SupportsRelatedObjectsManager(AssignedObjectsCountManager): """ Prefetch related objects by-default """ + def get_queryset(self): - return super().get_queryset().prefetch_related( - *SUPPORTS_RELATED_OBJECTS_PREFETCH_RELATED + return ( + super() + .get_queryset() + .prefetch_related(*SUPPORTS_RELATED_OBJECTS_PREFETCH_RELATED) ) @@ -68,17 +69,16 @@ class Support( NamedMixin.NonUnique, PriceMixin, BaseObject, - AutocompleteTooltipMixin + AutocompleteTooltipMixin, ): _allow_in_dashboard = True asset_type = models.PositiveSmallIntegerField( - choices=ObjectModelType(), default=ObjectModelType.all.id, + choices=ObjectModelType(), + default=ObjectModelType.all.id, ) contract_id = models.CharField( - verbose_name=_('contract ID'), - max_length=50, - blank=False + verbose_name=_("contract ID"), max_length=50, blank=False ) description = models.CharField(max_length=100, blank=True) date_from = models.DateField(null=True, blank=True) @@ -96,20 +96,13 @@ class Support( producer = models.CharField(max_length=100, blank=True) supplier = models.CharField(max_length=100, blank=True) serial_no = models.CharField( - verbose_name=_('serial number'), - max_length=100, - blank=True + verbose_name=_("serial number"), max_length=100, blank=True ) invoice_no = models.CharField( - verbose_name=_('invoice number'), - max_length=100, - blank=True, - db_index=True + verbose_name=_("invoice number"), max_length=100, blank=True, db_index=True ) invoice_date = models.DateField( - verbose_name=_('invoice date'), - null=True, - blank=True + verbose_name=_("invoice date"), null=True, blank=True ) period_in_months = models.IntegerField(null=True, blank=True) property_of = models.ForeignKey( @@ -134,18 +127,18 @@ class Support( ) base_objects = PolymorphicManyToManyField( BaseObject, - related_name='+', - through='BaseObjectsSupport', + related_name="+", + through="BaseObjectsSupport", ) autocomplete_tooltip_fields = [ - 'date_from', - 'date_to', - 'asset_type', - 'producer', - 'supplier', - 'serial_no', - 'support_type' + "date_from", + "date_to", + "asset_type", + "producer", + "supplier", + "serial_no", + "support_type", ] polymorphic_objects = PolymorphicQuerySet.as_manager() @@ -160,30 +153,22 @@ def get_natural_end_support(self): return naturaltime(datetime(*(self.date_to.timetuple()[:6]))) def __str__(self): - return '{} ({})'.format(self.name, self.date_to) + return "{} ({})".format(self.name, self.date_to) @property def autocomplete_str(self): - return '{} ({}, {})'.format( - str(self.name), self.date_to, self.supplier - ) + return "{} ({}, {})".format(str(self.name), self.date_to, self.supplier) -class BaseObjectsSupport( - AdminAbsoluteUrlMixin, - models.Model -): +class BaseObjectsSupport(AdminAbsoluteUrlMixin, models.Model): support = models.ForeignKey(Support, on_delete=models.CASCADE) baseobject = BaseObjectForeignKey( BaseObject, - verbose_name=_('Asset'), - related_name='supports', - limit_models=[ - 'back_office.BackOfficeAsset', - 'data_center.DataCenterAsset' - ], - on_delete=models.CASCADE + verbose_name=_("Asset"), + related_name="supports", + limit_models=["back_office.BackOfficeAsset", "data_center.DataCenterAsset"], + on_delete=models.CASCADE, ) class Meta: - unique_together = ('support', 'baseobject') + unique_together = ("support", "baseobject") diff --git a/src/ralph/supports/tests/factories.py b/src/ralph/supports/tests/factories.py index e96e155f30..21febceaf7 100644 --- a/src/ralph/supports/tests/factories.py +++ b/src/ralph/supports/tests/factories.py @@ -13,44 +13,66 @@ BaseObjectsSupport, Support, SupportStatus, - SupportType + SupportType, ) date_now = datetime.now().date() class SupportTypeFactory(DjangoModelFactory): - - name = factory.Iterator(['warranty', 'additional']) + name = factory.Iterator(["warranty", "additional"]) class Meta: model = SupportType - django_get_or_create = ['name'] + django_get_or_create = ["name"] class SupportFactory(DjangoModelFactory): - region = factory.SubFactory(RegionFactory) support_type = factory.SubFactory(SupportTypeFactory) status = SupportStatus.new - contract_id = factory.Sequence(lambda n: 'c{}'.format(n)) + contract_id = factory.Sequence(lambda n: "c{}".format(n)) date_to = date(2020, 12, 31) name = factory.Iterator( [ - 'cisco', 'hp', 'ibm', 'intel', 'dell', 'sun', 'google', 'juniper', - '2hp', 'ironport', 'microsoft', 'oracle', '3par', 'tk' + "cisco", + "hp", + "ibm", + "intel", + "dell", + "sun", + "google", + "juniper", + "2hp", + "ironport", + "microsoft", + "oracle", + "3par", + "tk", ] ) date_from = date_now - timedelta(days=15) date_to = date_now + timedelta(days=365) producer = factory.Iterator( [ - 'cisco', 'hp', 'ibm', 'intel', 'dell', 'sun', 'google', 'juniper', - '2hp', 'ironport', 'microsoft', 'oracle', '3par', 'tk' + "cisco", + "hp", + "ibm", + "intel", + "dell", + "sun", + "google", + "juniper", + "2hp", + "ironport", + "microsoft", + "oracle", + "3par", + "tk", ] ) serial_no = FuzzyText() - invoice_no = factory.Sequence(lambda n: 'Invoice number ' + str(n)) + invoice_no = factory.Sequence(lambda n: "Invoice number " + str(n)) invoice_date = date_now - timedelta(days=15) budget_info = factory.SubFactory(BudgetInfoFactory) property_of = factory.SubFactory(AssetHolderFactory) @@ -60,7 +82,6 @@ class Meta: class BaseObjectsSupportFactory(DjangoModelFactory): - baseobject = factory.SubFactory(BackOfficeAssetFactory) support = factory.SubFactory(SupportFactory) diff --git a/src/ralph/supports/tests/test_api.py b/src/ralph/supports/tests/test_api.py index 1fcab9c0b3..8065c02bf5 100644 --- a/src/ralph/supports/tests/test_api.py +++ b/src/ralph/supports/tests/test_api.py @@ -15,68 +15,62 @@ class SupportAPITests(RalphAPITestCase): def setUp(self): super().setUp() self.service_env = ServiceEnvironmentFactory() - self.support = SupportFactory( - name='support1', - service_env=self.service_env - ) + self.support = SupportFactory(name="support1", service_env=self.service_env) def test_get_supports_list(self): - url = reverse('support-list') - response = self.client.get(url, format='json') + url = reverse("support-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], Support.objects.count() - ) + self.assertEqual(response.data["count"], Support.objects.count()) def test_get_support_details(self): - url = reverse('support-detail', args=(self.support.id,)) - response = self.client.get(url, format='json') + url = reverse("support-detail", args=(self.support.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.support.name) - self.assertEqual(response.data['contract_id'], self.support.contract_id) - self.assertEqual(response.data['status'], 'new') + self.assertEqual(response.data["name"], self.support.name) + self.assertEqual(response.data["contract_id"], self.support.contract_id) + self.assertEqual(response.data["status"], "new") self.assertEqual( - response.data['support_type']['id'], self.support.support_type.id + response.data["support_type"]["id"], self.support.support_type.id ) self.assertEqual( - response.data['service_env']['service'], - self.service_env.service.name + response.data["service_env"]["service"], self.service_env.service.name ) self.assertEqual( - response.data['service_env']['environment'], - self.service_env.environment.name + response.data["service_env"]["environment"], + self.service_env.environment.name, ) # TODO: baseobjects def test_create_support(self): - region = Region.objects.create(name='EU') - url = reverse('support-list') + region = Region.objects.create(name="EU") + url = reverse("support-list") data = { - 'name': 'support2', - 'region': region.id, - 'contract_id': '12345', - 'status': 'new', - 'date_to': '2020-01-01', + "name": "support2", + "region": region.id, + "contract_id": "12345", + "status": "new", + "date_to": "2020-01-01", } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - support = Support.objects.get(pk=response.data['id']) - self.assertEqual(support.name, 'support2') + support = Support.objects.get(pk=response.data["id"]) + self.assertEqual(support.name, "support2") self.assertEqual(support.region, region) - self.assertEqual(support.contract_id, '12345') + self.assertEqual(support.contract_id, "12345") self.assertEqual(support.status, SupportStatus.new.id) self.assertEqual(support.date_to, date(2020, 1, 1)) def test_patch_support(self): - url = reverse('support-detail', args=(self.support.id,)) + url = reverse("support-detail", args=(self.support.id,)) data = { - 'name': 'support2', - 'contract_id': '12345', - 'date_to': '2015-12-31', + "name": "support2", + "contract_id": "12345", + "date_to": "2015-12-31", } - response = self.client.patch(url, data, format='json') + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.support.refresh_from_db() - self.assertEqual(self.support.name, 'support2') - self.assertEqual(self.support.contract_id, '12345') + self.assertEqual(self.support.name, "support2") + self.assertEqual(self.support.contract_id, "12345") self.assertEqual(self.support.date_to, date(2015, 12, 31)) diff --git a/src/ralph/supports/tests/test_autocomplete.py b/src/ralph/supports/tests/test_autocomplete.py index f11a97db1d..0834683d61 100644 --- a/src/ralph/supports/tests/test_autocomplete.py +++ b/src/ralph/supports/tests/test_autocomplete.py @@ -10,48 +10,47 @@ class SupportAutocompleteTest(TestCase, ClientMixin): - def setUp(self): super().setUp() self.support = SupportFactory( - name='test1', - support_type=SupportTypeFactory(name='type1'), - supplier='supplier1' + name="test1", + support_type=SupportTypeFactory(name="type1"), + supplier="supplier1", ) - self.login_as_user(username='test') + self.login_as_user(username="test") def test_autocomplete_json(self): client_url = reverse( - 'autocomplete-list', kwargs={ - 'app': 'supports', - 'model': 'baseobjectssupport', - 'field': 'support' - } + "autocomplete-list", + kwargs={ + "app": "supports", + "model": "baseobjectssupport", + "field": "support", + }, ) - response = self.client.get(client_url, {QUERY_PARAM: 'test1'}) + response = self.client.get(client_url, {QUERY_PARAM: "test1"}) expected_html = ( - 'Date from: {date_from}\n' - 'Date to: {date_to}\n' - 'Asset type: all\n' - 'Producer: {producer}\n' - 'Supplier: supplier1\n' - 'Serial number: {serial_no}\n' - 'Support type: type1\n' + "Date from: {date_from}\n" + "Date to: {date_to}\n" + "Asset type: all\n" + "Producer: {producer}\n" + "Supplier: supplier1\n" + "Serial number: {serial_no}\n" + "Support type: type1\n" ).format( date_to=self.support.date_to, producer=self.support.producer, date_from=self.support.date_from, - serial_no=self.support.serial_no + serial_no=self.support.serial_no, ) - data = json.loads(str(response.content, 'utf-8'))['results'][0] + data = json.loads(str(response.content, "utf-8"))["results"][0] self.assertEqual( - data['__str__'], '{} ({}, {})'.format( - str(self.support.name), - self.support.date_to, - self.support.supplier - ) + data["__str__"], + "{} ({}, {})".format( + str(self.support.name), self.support.date_to, self.support.supplier + ), ) - self.assertHTMLEqual(data['tooltip'], expected_html) + self.assertHTMLEqual(data["tooltip"], expected_html) diff --git a/src/ralph/tests/__init__.py b/src/ralph/tests/__init__.py index 9be7c4ca00..a26a6222fa 100644 --- a/src/ralph/tests/__init__.py +++ b/src/ralph/tests/__init__.py @@ -1,6 +1,6 @@ from ralph.admin.sites import RalphAdminSite from ralph.tests.base import RalphTestCase -ralph_test_site = RalphAdminSite(name='ralph_test_site') +ralph_test_site = RalphAdminSite(name="ralph_test_site") -__all__ = ['RalphTestCase'] +__all__ = ["RalphTestCase"] diff --git a/src/ralph/tests/admin.py b/src/ralph/tests/admin.py index d400f07b1b..bdeccefac7 100644 --- a/src/ralph/tests/admin.py +++ b/src/ralph/tests/admin.py @@ -14,43 +14,43 @@ Foo, Order, PolymorphicTestModel, - TestManufacturer + TestManufacturer, ) @register(Car) class CarAdmin(RalphAdmin): - ordering = ['name'] - list_filter = ['year'] - search_fields = ['name', 'foos__bar'] + ordering = ["name"] + list_filter = ["year"] + search_fields = ["name", "foos__bar"] @register(Bar) class BarAdmin(RalphAdmin): - list_filter = ['date', 'name', 'created', 'price', 'count'] + list_filter = ["date", "name", "created", "price", "count"] class BarsM2MInline(RalphTabularM2MInline): model = Foo.bars.through - fields = ('name', 'date', 'price', 'count') + fields = ("name", "date", "price", "count") extra = 1 - verbose_name = _('Bars') + verbose_name = _("Bars") @register(Foo) class FooAdmin(RalphAdmin): inlines = [BarsM2MInline] - list_filter = ['bar'] + list_filter = ["bar"] @register(Car2) class Car2Admin(RalphAdmin): - list_filter = ['manufacturer'] + list_filter = ["manufacturer"] @register(TestManufacturer) class ManufacturerAdmin(RalphAdmin): - ordering = ['name', '-country'] + ordering = ["name", "-country"] @register(Order) @@ -61,4 +61,4 @@ class OrderAdmin(AttachmentsMixin, TransitionAdminMixin, RalphAdmin): @register(PolymorphicTestModel) class PolymorphicTestModelAdmin(RalphAdmin): inlines = [NetworkInline] - exclude = ['service_env', 'parent', 'content_type'] + exclude = ["service_env", "parent", "content_type"] diff --git a/src/ralph/tests/factories.py b/src/ralph/tests/factories.py index e6a83636bd..e65a59e578 100644 --- a/src/ralph/tests/factories.py +++ b/src/ralph/tests/factories.py @@ -8,10 +8,11 @@ class UserFactory(factory.Factory): """ User *password* is 'ralph'. """ + class Meta: model = get_user_model() - username = factory.Sequence(lambda n: 'user_{}'.format(n)) + username = factory.Sequence(lambda n: "user_{}".format(n)) @factory.post_generation def groups(self, create, extracted, **kwargs): @@ -25,21 +26,20 @@ def groups(self, create, extracted, **kwargs): @factory.lazy_attribute def email(self): - return '%s@example.com' % self.username + return "%s@example.com" % self.username @classmethod def _generate(cls, create, attrs): user = super(UserFactory, cls)._generate(create, attrs) - user.set_password('ralph') + user.set_password("ralph") user.save() return user class TestManufacturerFactory(factory.django.DjangoModelFactory): - - name = factory.Iterator(['Foxconn', 'Brother', 'Nokia', 'HTC']) - country = factory.Iterator(['Poland', 'Germany', 'Italy']) + name = factory.Iterator(["Foxconn", "Brother", "Nokia", "HTC"]) + country = factory.Iterator(["Poland", "Germany", "Italy"]) class Meta: model = TestManufacturer - django_get_or_create = ['name', 'country'] + django_get_or_create = ["name", "country"] diff --git a/src/ralph/tests/migrations/0001_initial.py b/src/ralph/tests/migrations/0001_initial.py index 90776dd4bd..07adc51723 100644 --- a/src/ralph/tests/migrations/0001_initial.py +++ b/src/ralph/tests/migrations/0001_initial.py @@ -8,65 +8,133 @@ class Migration(migrations.Migration): - - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Car', + name="Car", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('year', models.PositiveSmallIntegerField()), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=50)), + ("year", models.PositiveSmallIntegerField()), ], ), migrations.CreateModel( - name='Foo', + name="Foo", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('bar', models.CharField(max_length=50, verbose_name='bar')), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ("bar", models.CharField(max_length=50, verbose_name="bar")), ], bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='Manufacturer', + name="Manufacturer", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('country', models.CharField(max_length=50)), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=50)), + ("country", models.CharField(max_length=50)), ], ), migrations.CreateModel( - name='Order', + name="Order", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('status', ralph.lib.transitions.fields.TransitionField(choices=[(1, 'new'), (2, 'to_send'), (3, 'sended')], default=1)), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ( + "status", + ralph.lib.transitions.fields.TransitionField( + choices=[(1, "new"), (2, "to_send"), (3, "sended")], default=1 + ), + ), ], bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='TestAsset', + name="TestAsset", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('hostname', models.CharField(max_length=50)), - ('sn', models.CharField(unique=True, blank=True, null=True, max_length=200)), - ('barcode', models.CharField(unique=True, blank=True, null=True, default=None, max_length=200)), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ("hostname", models.CharField(max_length=50)), + ( + "sn", + models.CharField( + unique=True, blank=True, null=True, max_length=200 + ), + ), + ( + "barcode", + models.CharField( + unique=True, blank=True, null=True, default=None, max_length=200 + ), + ), ], ), migrations.AddField( - model_name='car', - name='manufacturer', - field=models.ForeignKey(to='tests.Manufacturer', on_delete=django.db.models.deletion.CASCADE), + model_name="car", + name="manufacturer", + field=models.ForeignKey( + to="tests.Manufacturer", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.CreateModel( - name='BaseObjectForeignKeyModel', + name="BaseObjectForeignKeyModel", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('base_object', ralph.lib.mixins.fields.BaseObjectForeignKey( - verbose_name='Asset', related_name='licences', - to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE) - ) + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ( + "base_object", + ralph.lib.mixins.fields.BaseObjectForeignKey( + verbose_name="Asset", + related_name="licences", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], ), ] diff --git a/src/ralph/tests/migrations/0002_auto_20160119_0914.py b/src/ralph/tests/migrations/0002_auto_20160119_0914.py index 43759aac44..41087865cc 100644 --- a/src/ralph/tests/migrations/0002_auto_20160119_0914.py +++ b/src/ralph/tests/migrations/0002_auto_20160119_0914.py @@ -7,22 +7,37 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0001_initial'), + ("tests", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Car2', + name="Car2", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)), - ('manufacturer', models.ForeignKey(to='tests.Manufacturer', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + serialize=False, + primary_key=True, + ), + ), + ( + "manufacturer", + models.ForeignKey( + to="tests.Manufacturer", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], ), migrations.AlterField( - model_name='baseobjectforeignkeymodel', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE), + model_name="baseobjectforeignkeymodel", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + to="assets.BaseObject", on_delete=django.db.models.deletion.CASCADE + ), ), ] diff --git a/src/ralph/tests/migrations/0003_bar.py b/src/ralph/tests/migrations/0003_bar.py index e89adcc695..9109aa44d7 100644 --- a/src/ralph/tests/migrations/0003_bar.py +++ b/src/ralph/tests/migrations/0003_bar.py @@ -5,21 +5,28 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0002_auto_20160119_0914'), + ("tests", "0002_auto_20160119_0914"), ] operations = [ migrations.CreateModel( - name='Bar', + name="Bar", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('created', models.DateTimeField(auto_now_add=True)), - ('date', models.DateField()), - ('price', models.DecimalField(max_digits=5, decimal_places=2)), - ('count', models.IntegerField(default=0)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ("created", models.DateTimeField(auto_now_add=True)), + ("date", models.DateField()), + ("price", models.DecimalField(max_digits=5, decimal_places=2)), + ("count", models.IntegerField(default=0)), ], ), ] diff --git a/src/ralph/tests/migrations/0004_car_foos.py b/src/ralph/tests/migrations/0004_car_foos.py index b3cc0f6edf..370e2e6a8d 100644 --- a/src/ralph/tests/migrations/0004_car_foos.py +++ b/src/ralph/tests/migrations/0004_car_foos.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0003_bar'), + ("tests", "0003_bar"), ] operations = [ migrations.AddField( - model_name='car', - name='foos', - field=models.ManyToManyField(to='tests.Foo'), + model_name="car", + name="foos", + field=models.ManyToManyField(to="tests.Foo"), ), ] diff --git a/src/ralph/tests/migrations/0005_bar_foos.py b/src/ralph/tests/migrations/0005_bar_foos.py index b42018fa87..df0fd52be4 100644 --- a/src/ralph/tests/migrations/0005_bar_foos.py +++ b/src/ralph/tests/migrations/0005_bar_foos.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0004_car_foos'), + ("tests", "0004_car_foos"), ] operations = [ migrations.AddField( - model_name='bar', - name='foos', - field=models.ManyToManyField(blank=True, to='tests.Foo', related_name='bars'), + model_name="bar", + name="foos", + field=models.ManyToManyField( + blank=True, to="tests.Foo", related_name="bars" + ), ), ] diff --git a/src/ralph/tests/migrations/0006_auto_20160607_0842.py b/src/ralph/tests/migrations/0006_auto_20160607_0842.py index f680468957..1839b792e5 100644 --- a/src/ralph/tests/migrations/0006_auto_20160607_0842.py +++ b/src/ralph/tests/migrations/0006_auto_20160607_0842.py @@ -8,39 +8,69 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0012_auto_20160606_1409'), - ('tests', '0005_bar_foos'), + ("assets", "0012_auto_20160606_1409"), + ("tests", "0005_bar_foos"), ] operations = [ migrations.CreateModel( - name='AsyncOrder', + name="AsyncOrder", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)), - ('status', ralph.lib.transitions.fields.TransitionField(choices=[(1, 'new'), (2, 'to_send'), (3, 'sended')], default=1)), - ('name', models.CharField(max_length=100)), - ('counter', models.PositiveSmallIntegerField(default=1)), - ('username', models.CharField(max_length=100, blank=True, null=True)), - ('foo', models.ForeignKey(blank=True, to='tests.Foo', null=True, on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + serialize=False, + primary_key=True, + ), + ), + ( + "status", + ralph.lib.transitions.fields.TransitionField( + choices=[(1, "new"), (2, "to_send"), (3, "sended")], default=1 + ), + ), + ("name", models.CharField(max_length=100)), + ("counter", models.PositiveSmallIntegerField(default=1)), + ("username", models.CharField(max_length=100, blank=True, null=True)), + ( + "foo", + models.ForeignKey( + blank=True, + to="tests.Foo", + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='PolymorphicTestModel', + name="PolymorphicTestModel", fields=[ - ('baseobject_ptr', models.OneToOneField(auto_created=True, serialize=False, primary_key=True, to='assets.BaseObject', parent_link=True, on_delete=django.db.models.deletion.CASCADE)), - ('hostname', models.CharField(max_length=50)), + ( + "baseobject_ptr", + models.OneToOneField( + auto_created=True, + serialize=False, + primary_key=True, + to="assets.BaseObject", + parent_link=True, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("hostname", models.CharField(max_length=50)), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject'), + bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, "assets.baseobject"), ), migrations.AddField( - model_name='order', - name='remarks', - field=models.CharField(max_length=255, blank=True, default=''), + model_name="order", + name="remarks", + field=models.CharField(max_length=255, blank=True, default=""), ), ] diff --git a/src/ralph/tests/migrations/0007_auto_20160808_1324.py b/src/ralph/tests/migrations/0007_auto_20160808_1324.py index 610b2a4e2d..6b4a88754f 100644 --- a/src/ralph/tests/migrations/0007_auto_20160808_1324.py +++ b/src/ralph/tests/migrations/0007_auto_20160808_1324.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0006_auto_20160607_0842'), + ("tests", "0006_auto_20160607_0842"), ] operations = [ migrations.AlterField( - model_name='bar', - name='date', + model_name="bar", + name="date", field=models.DateField(blank=True, null=True), ), ] diff --git a/src/ralph/tests/migrations/0008_auto_20200909_1322.py b/src/ralph/tests/migrations/0008_auto_20200909_1322.py index ec244d660b..be546ef105 100644 --- a/src/ralph/tests/migrations/0008_auto_20200909_1322.py +++ b/src/ralph/tests/migrations/0008_auto_20200909_1322.py @@ -1,26 +1,227 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import djmoney.models.fields from decimal import Decimal class Migration(migrations.Migration): - dependencies = [ - ('tests', '0007_auto_20160808_1324'), + ("tests", "0007_auto_20160808_1324"), ] operations = [ migrations.AddField( - model_name='bar', - name='price_currency', - field=djmoney.models.fields.CurrencyField(max_length=3, default='XXX', editable=False, choices=[('XXX', '---'), ('AED', 'AED'), ('AFN', 'AFN'), ('ALL', 'ALL'), ('AMD', 'AMD'), ('ANG', 'ANG'), ('AOA', 'AOA'), ('ARS', 'ARS'), ('AUD', 'AUD'), ('AWG', 'AWG'), ('AZN', 'AZN'), ('BAM', 'BAM'), ('BBD', 'BBD'), ('BDT', 'BDT'), ('BGN', 'BGN'), ('BHD', 'BHD'), ('BIF', 'BIF'), ('BMD', 'BMD'), ('BND', 'BND'), ('BOB', 'BOB'), ('BOV', 'BOV'), ('BRL', 'BRL'), ('BSD', 'BSD'), ('BTN', 'BTN'), ('BWP', 'BWP'), ('BYN', 'BYN'), ('BYR', 'BYR'), ('BZD', 'BZD'), ('CAD', 'CAD'), ('CDF', 'CDF'), ('CHE', 'CHE'), ('CHF', 'CHF'), ('CHW', 'CHW'), ('CLF', 'CLF'), ('CLP', 'CLP'), ('CNY', 'CNY'), ('COP', 'COP'), ('COU', 'COU'), ('CRC', 'CRC'), ('CUC', 'CUC'), ('CUP', 'CUP'), ('CVE', 'CVE'), ('CZK', 'CZK'), ('DJF', 'DJF'), ('DKK', 'DKK'), ('DOP', 'DOP'), ('DZD', 'DZD'), ('EGP', 'EGP'), ('ERN', 'ERN'), ('ETB', 'ETB'), ('EUR', 'EUR'), ('FJD', 'FJD'), ('FKP', 'FKP'), ('GBP', 'GBP'), ('GEL', 'GEL'), ('GHS', 'GHS'), ('GIP', 'GIP'), ('GMD', 'GMD'), ('GNF', 'GNF'), ('GTQ', 'GTQ'), ('GYD', 'GYD'), ('HKD', 'HKD'), ('HNL', 'HNL'), ('HRK', 'HRK'), ('HTG', 'HTG'), ('HUF', 'HUF'), ('IDR', 'IDR'), ('ILS', 'ILS'), ('IMP', 'IMP'), ('INR', 'INR'), ('IQD', 'IQD'), ('IRR', 'IRR'), ('ISK', 'ISK'), ('JMD', 'JMD'), ('JOD', 'JOD'), ('JPY', 'JPY'), ('KES', 'KES'), ('KGS', 'KGS'), ('KHR', 'KHR'), ('KMF', 'KMF'), ('KPW', 'KPW'), ('KRW', 'KRW'), ('KWD', 'KWD'), ('KYD', 'KYD'), ('KZT', 'KZT'), ('LAK', 'LAK'), ('LBP', 'LBP'), ('LKR', 'LKR'), ('LRD', 'LRD'), ('LSL', 'LSL'), ('LTL', 'LTL'), ('LVL', 'LVL'), ('LYD', 'LYD'), ('MAD', 'MAD'), ('MDL', 'MDL'), ('MGA', 'MGA'), ('MKD', 'MKD'), ('MMK', 'MMK'), ('MNT', 'MNT'), ('MOP', 'MOP'), ('MRO', 'MRO'), ('MUR', 'MUR'), ('MVR', 'MVR'), ('MWK', 'MWK'), ('MXN', 'MXN'), ('MXV', 'MXV'), ('MYR', 'MYR'), ('MZN', 'MZN'), ('NAD', 'NAD'), ('NGN', 'NGN'), ('NIO', 'NIO'), ('NOK', 'NOK'), ('NPR', 'NPR'), ('NZD', 'NZD'), ('OMR', 'OMR'), ('PAB', 'PAB'), ('PEN', 'PEN'), ('PGK', 'PGK'), ('PHP', 'PHP'), ('PKR', 'PKR'), ('PLN', 'PLN'), ('PYG', 'PYG'), ('QAR', 'QAR'), ('RON', 'RON'), ('RSD', 'RSD'), ('RUB', 'RUB'), ('RWF', 'RWF'), ('SAR', 'SAR'), ('SBD', 'SBD'), ('SCR', 'SCR'), ('SDG', 'SDG'), ('SEK', 'SEK'), ('SGD', 'SGD'), ('SHP', 'SHP'), ('SLL', 'SLL'), ('SOS', 'SOS'), ('SRD', 'SRD'), ('SSP', 'SSP'), ('STD', 'STD'), ('SVC', 'SVC'), ('SYP', 'SYP'), ('SZL', 'SZL'), ('THB', 'THB'), ('TJS', 'TJS'), ('TMM', 'TMM'), ('TMT', 'TMT'), ('TND', 'TND'), ('TOP', 'TOP'), ('TRY', 'TRY'), ('TTD', 'TTD'), ('TVD', 'TVD'), ('TWD', 'TWD'), ('TZS', 'TZS'), ('UAH', 'UAH'), ('UGX', 'UGX'), ('USD', 'USD'), ('USN', 'USN'), ('UYI', 'UYI'), ('UYU', 'UYU'), ('UZS', 'UZS'), ('VEF', 'VEF'), ('VND', 'VND'), ('VUV', 'VUV'), ('WST', 'WST'), ('XAF', 'XAF'), ('XAG', 'XAG'), ('XAU', 'XAU'), ('XBA', 'XBA'), ('XBB', 'XBB'), ('XBC', 'XBC'), ('XBD', 'XBD'), ('XCD', 'XCD'), ('XDR', 'XDR'), ('XFO', 'XFO'), ('XFU', 'XFU'), ('XOF', 'XOF'), ('XPD', 'XPD'), ('XPF', 'XPF'), ('XPT', 'XPT'), ('XSU', 'XSU'), ('XTS', 'XTS'), ('XUA', 'XUA'), ('XYZ', 'XYZ'), ('YER', 'YER'), ('ZAR', 'ZAR'), ('ZMK', 'ZMK'), ('ZMW', 'ZMW'), ('ZWD', 'ZWD'), ('ZWL', 'ZWL'), ('ZWN', 'ZWN')]), + model_name="bar", + name="price_currency", + field=djmoney.models.fields.CurrencyField( + max_length=3, + default="XXX", + editable=False, + choices=[ + ("XXX", "---"), + ("AED", "AED"), + ("AFN", "AFN"), + ("ALL", "ALL"), + ("AMD", "AMD"), + ("ANG", "ANG"), + ("AOA", "AOA"), + ("ARS", "ARS"), + ("AUD", "AUD"), + ("AWG", "AWG"), + ("AZN", "AZN"), + ("BAM", "BAM"), + ("BBD", "BBD"), + ("BDT", "BDT"), + ("BGN", "BGN"), + ("BHD", "BHD"), + ("BIF", "BIF"), + ("BMD", "BMD"), + ("BND", "BND"), + ("BOB", "BOB"), + ("BOV", "BOV"), + ("BRL", "BRL"), + ("BSD", "BSD"), + ("BTN", "BTN"), + ("BWP", "BWP"), + ("BYN", "BYN"), + ("BYR", "BYR"), + ("BZD", "BZD"), + ("CAD", "CAD"), + ("CDF", "CDF"), + ("CHE", "CHE"), + ("CHF", "CHF"), + ("CHW", "CHW"), + ("CLF", "CLF"), + ("CLP", "CLP"), + ("CNY", "CNY"), + ("COP", "COP"), + ("COU", "COU"), + ("CRC", "CRC"), + ("CUC", "CUC"), + ("CUP", "CUP"), + ("CVE", "CVE"), + ("CZK", "CZK"), + ("DJF", "DJF"), + ("DKK", "DKK"), + ("DOP", "DOP"), + ("DZD", "DZD"), + ("EGP", "EGP"), + ("ERN", "ERN"), + ("ETB", "ETB"), + ("EUR", "EUR"), + ("FJD", "FJD"), + ("FKP", "FKP"), + ("GBP", "GBP"), + ("GEL", "GEL"), + ("GHS", "GHS"), + ("GIP", "GIP"), + ("GMD", "GMD"), + ("GNF", "GNF"), + ("GTQ", "GTQ"), + ("GYD", "GYD"), + ("HKD", "HKD"), + ("HNL", "HNL"), + ("HRK", "HRK"), + ("HTG", "HTG"), + ("HUF", "HUF"), + ("IDR", "IDR"), + ("ILS", "ILS"), + ("IMP", "IMP"), + ("INR", "INR"), + ("IQD", "IQD"), + ("IRR", "IRR"), + ("ISK", "ISK"), + ("JMD", "JMD"), + ("JOD", "JOD"), + ("JPY", "JPY"), + ("KES", "KES"), + ("KGS", "KGS"), + ("KHR", "KHR"), + ("KMF", "KMF"), + ("KPW", "KPW"), + ("KRW", "KRW"), + ("KWD", "KWD"), + ("KYD", "KYD"), + ("KZT", "KZT"), + ("LAK", "LAK"), + ("LBP", "LBP"), + ("LKR", "LKR"), + ("LRD", "LRD"), + ("LSL", "LSL"), + ("LTL", "LTL"), + ("LVL", "LVL"), + ("LYD", "LYD"), + ("MAD", "MAD"), + ("MDL", "MDL"), + ("MGA", "MGA"), + ("MKD", "MKD"), + ("MMK", "MMK"), + ("MNT", "MNT"), + ("MOP", "MOP"), + ("MRO", "MRO"), + ("MUR", "MUR"), + ("MVR", "MVR"), + ("MWK", "MWK"), + ("MXN", "MXN"), + ("MXV", "MXV"), + ("MYR", "MYR"), + ("MZN", "MZN"), + ("NAD", "NAD"), + ("NGN", "NGN"), + ("NIO", "NIO"), + ("NOK", "NOK"), + ("NPR", "NPR"), + ("NZD", "NZD"), + ("OMR", "OMR"), + ("PAB", "PAB"), + ("PEN", "PEN"), + ("PGK", "PGK"), + ("PHP", "PHP"), + ("PKR", "PKR"), + ("PLN", "PLN"), + ("PYG", "PYG"), + ("QAR", "QAR"), + ("RON", "RON"), + ("RSD", "RSD"), + ("RUB", "RUB"), + ("RWF", "RWF"), + ("SAR", "SAR"), + ("SBD", "SBD"), + ("SCR", "SCR"), + ("SDG", "SDG"), + ("SEK", "SEK"), + ("SGD", "SGD"), + ("SHP", "SHP"), + ("SLL", "SLL"), + ("SOS", "SOS"), + ("SRD", "SRD"), + ("SSP", "SSP"), + ("STD", "STD"), + ("SVC", "SVC"), + ("SYP", "SYP"), + ("SZL", "SZL"), + ("THB", "THB"), + ("TJS", "TJS"), + ("TMM", "TMM"), + ("TMT", "TMT"), + ("TND", "TND"), + ("TOP", "TOP"), + ("TRY", "TRY"), + ("TTD", "TTD"), + ("TVD", "TVD"), + ("TWD", "TWD"), + ("TZS", "TZS"), + ("UAH", "UAH"), + ("UGX", "UGX"), + ("USD", "USD"), + ("USN", "USN"), + ("UYI", "UYI"), + ("UYU", "UYU"), + ("UZS", "UZS"), + ("VEF", "VEF"), + ("VND", "VND"), + ("VUV", "VUV"), + ("WST", "WST"), + ("XAF", "XAF"), + ("XAG", "XAG"), + ("XAU", "XAU"), + ("XBA", "XBA"), + ("XBB", "XBB"), + ("XBC", "XBC"), + ("XBD", "XBD"), + ("XCD", "XCD"), + ("XDR", "XDR"), + ("XFO", "XFO"), + ("XFU", "XFU"), + ("XOF", "XOF"), + ("XPD", "XPD"), + ("XPF", "XPF"), + ("XPT", "XPT"), + ("XSU", "XSU"), + ("XTS", "XTS"), + ("XUA", "XUA"), + ("XYZ", "XYZ"), + ("YER", "YER"), + ("ZAR", "ZAR"), + ("ZMK", "ZMK"), + ("ZMW", "ZMW"), + ("ZWD", "ZWD"), + ("ZWL", "ZWL"), + ("ZWN", "ZWN"), + ], + ), ), migrations.AlterField( - model_name='bar', - name='price', - field=djmoney.models.fields.MoneyField(null=True, default=Decimal('0'), max_digits=15, decimal_places=2, default_currency='XXX'), + model_name="bar", + name="price", + field=djmoney.models.fields.MoneyField( + null=True, + default=Decimal("0"), + max_digits=15, + decimal_places=2, + default_currency="XXX", + ), ), ] diff --git a/src/ralph/tests/migrations/0009_auto_20240621_1009.py b/src/ralph/tests/migrations/0009_auto_20240621_1009.py index 62b8cb37b9..a895023a3e 100644 --- a/src/ralph/tests/migrations/0009_auto_20240621_1009.py +++ b/src/ralph/tests/migrations/0009_auto_20240621_1009.py @@ -7,16 +7,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0008_auto_20200909_1322'), + ("tests", "0008_auto_20200909_1322"), ] operations = [ migrations.AlterModelManagers( - name='polymorphictestmodel', + name="polymorphictestmodel", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/tests/migrations/0010_auto_20240621_1217.py b/src/ralph/tests/migrations/0010_auto_20240621_1217.py index f65bb15d84..7cb1b7f60e 100644 --- a/src/ralph/tests/migrations/0010_auto_20240621_1217.py +++ b/src/ralph/tests/migrations/0010_auto_20240621_1217.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0009_auto_20240621_1009'), + ("tests", "0009_auto_20240621_1009"), ] operations = [ migrations.AlterField( - model_name='baseobjectforeignkeymodel', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, on_delete=django.db.models.deletion.CASCADE, to='assets.BaseObject'), + model_name="baseobjectforeignkeymodel", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, + on_delete=django.db.models.deletion.CASCADE, + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/tests/migrations/0011_auto_20240621_1231.py b/src/ralph/tests/migrations/0011_auto_20240621_1231.py index 52e3c40642..eeaad488cb 100644 --- a/src/ralph/tests/migrations/0011_auto_20240621_1231.py +++ b/src/ralph/tests/migrations/0011_auto_20240621_1231.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0010_auto_20240621_1217'), + ("tests", "0010_auto_20240621_1217"), ] operations = [ migrations.AlterField( - model_name='baseobjectforeignkeymodel', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, on_delete=django.db.models.deletion.CASCADE, to='assets.BaseObject'), + model_name="baseobjectforeignkeymodel", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, + on_delete=django.db.models.deletion.CASCADE, + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/tests/migrations/0012_auto_20240621_1355.py b/src/ralph/tests/migrations/0012_auto_20240621_1355.py index 36785a0b8c..046a14b8be 100644 --- a/src/ralph/tests/migrations/0012_auto_20240621_1355.py +++ b/src/ralph/tests/migrations/0012_auto_20240621_1355.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0011_auto_20240621_1231'), + ("tests", "0011_auto_20240621_1231"), ] operations = [ migrations.AlterField( - model_name='baseobjectforeignkeymodel', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, on_delete=django.db.models.deletion.CASCADE, to='assets.BaseObject'), + model_name="baseobjectforeignkeymodel", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, + on_delete=django.db.models.deletion.CASCADE, + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/tests/migrations/0013_auto_20240627_1512.py b/src/ralph/tests/migrations/0013_auto_20240627_1512.py index 904ac59ece..2a170ec393 100644 --- a/src/ralph/tests/migrations/0013_auto_20240627_1512.py +++ b/src/ralph/tests/migrations/0013_auto_20240627_1512.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0012_auto_20240621_1355'), + ("tests", "0012_auto_20240621_1355"), ] operations = [ migrations.AlterField( - model_name='baseobjectforeignkeymodel', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, on_delete=django.db.models.deletion.CASCADE, to='assets.BaseObject'), + model_name="baseobjectforeignkeymodel", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_choices_to=ralph.lib.mixins.fields.BaseObjectForeignKey.limit_choices, + on_delete=django.db.models.deletion.CASCADE, + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/tests/migrations/0014_auto_20240628_1213.py b/src/ralph/tests/migrations/0014_auto_20240628_1213.py index 5931a1d4ca..d777963534 100644 --- a/src/ralph/tests/migrations/0014_auto_20240628_1213.py +++ b/src/ralph/tests/migrations/0014_auto_20240628_1213.py @@ -6,15 +6,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0013_auto_20240627_1512'), + ("tests", "0013_auto_20240627_1512"), ] operations = [ migrations.AlterField( - model_name='baseobjectforeignkeymodel', - name='base_object', - field=ralph.lib.mixins.fields.BaseObjectForeignKey(limit_models=['back_office.BackOfficeAsset', 'data_center.DataCenterAsset'], on_delete=django.db.models.deletion.CASCADE, to='assets.BaseObject'), + model_name="baseobjectforeignkeymodel", + name="base_object", + field=ralph.lib.mixins.fields.BaseObjectForeignKey( + limit_models=[ + "back_office.BackOfficeAsset", + "data_center.DataCenterAsset", + ], + on_delete=django.db.models.deletion.CASCADE, + to="assets.BaseObject", + ), ), ] diff --git a/src/ralph/tests/migrations/0015_auto_20240918_1428.py b/src/ralph/tests/migrations/0015_auto_20240918_1428.py index 3571413256..bce37aae00 100644 --- a/src/ralph/tests/migrations/0015_auto_20240918_1428.py +++ b/src/ralph/tests/migrations/0015_auto_20240918_1428.py @@ -4,14 +4,13 @@ class Migration(migrations.Migration): - dependencies = [ - ('tests', '0014_auto_20240628_1213'), + ("tests", "0014_auto_20240628_1213"), ] operations = [ migrations.RenameModel( - old_name='Manufacturer', - new_name='TestManufacturer', + old_name="Manufacturer", + new_name="TestManufacturer", ), ] diff --git a/src/ralph/tests/mixins.py b/src/ralph/tests/mixins.py index 4e946fa046..c6dedd3a42 100644 --- a/src/ralph/tests/mixins.py +++ b/src/ralph/tests/mixins.py @@ -8,8 +8,7 @@ class ClientMixin(object): - - def login_as_user(self, user=None, password='ralph', *args, **kwargs): + def login_as_user(self, user=None, password="ralph", *args, **kwargs): if not user: user = UserFactory(*args, **kwargs) user.is_superuser = True @@ -23,6 +22,7 @@ class ReloadUrlsMixin(object): """ Use this mixin if you register dynamically models to admin. """ + def reload_urls(self): """ Reload all url configs specified in `URLCONF_MODULES` list in settings. diff --git a/src/ralph/tests/models.py b/src/ralph/tests/models.py index cadc9aa186..ff3aa4898b 100644 --- a/src/ralph/tests/models.py +++ b/src/ralph/tests/models.py @@ -9,11 +9,10 @@ from ralph.attachments.helpers import add_attachment_from_disk from ralph.lib.mixins.fields import BaseObjectForeignKey from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, PriceMixin -from ralph.lib.polymorphic.models import PolymorphicQuerySet from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.exceptions import ( FreezeAsyncTransition, - RescheduleAsyncTransitionActionLater + RescheduleAsyncTransitionActionLater, ) from ralph.lib.transitions.fields import TransitionField from ralph.lib.transitions.models import TransitionWorkflowBase @@ -22,16 +21,16 @@ class OrderStatus(Choices): _ = Choices.Choice - new = _('new') - to_send = _('to_send') - sended = _('sended') + new = _("new") + to_send = _("to_send") + sended = _("sended") class Foo(AdminAbsoluteUrlMixin, models.Model): - bar = models.CharField('bar', max_length=50) + bar = models.CharField("bar", max_length=50) def __str__(self): - return 'Foo: {} / {}'.format(self.id, self.bar) + return "Foo: {} / {}".format(self.id, self.bar) class TestManufacturer(AdminAbsoluteUrlMixin, models.Model): @@ -44,7 +43,7 @@ class Car(AdminAbsoluteUrlMixin, models.Model): year = models.PositiveSmallIntegerField() manufacturer = models.ForeignKey(TestManufacturer, on_delete=models.CASCADE) manufacturer._autocomplete = False - manufacturer._filter_title = 'test' + manufacturer._filter_title = "test" foos = models.ManyToManyField(Foo) @classmethod @@ -61,36 +60,30 @@ class Bar(AdminAbsoluteUrlMixin, PriceMixin, models.Model): created = models.DateTimeField(auto_now_add=True) date = models.DateField(blank=True, null=True) count = models.IntegerField(default=0) - foos = models.ManyToManyField(Foo, related_name='bars', blank=True) + foos = models.ManyToManyField(Foo, related_name="bars", blank=True) -class Order( - AdminAbsoluteUrlMixin, - models.Model, - metaclass=TransitionWorkflowBase -): +class Order(AdminAbsoluteUrlMixin, models.Model, metaclass=TransitionWorkflowBase): status = TransitionField( default=OrderStatus.new.id, choices=OrderStatus(), ) - remarks = models.CharField(max_length=255, blank=True, default='') + remarks = models.CharField(max_length=255, blank=True, default="") @classmethod @transition_action(return_attachment=True) def pack(cls, instances, **kwargs): - requester = kwargs.get('requester') - path = os.path.join(tempfile.gettempdir(), 'test.txt') - with open(path, 'w') as f: - f.write('test') - return add_attachment_from_disk( - instances, path, requester, 'pack action' - ) + requester = kwargs.get("requester") + path = os.path.join(tempfile.gettempdir(), "test.txt") + with open(path, "w") as f: + f.write("test") + return add_attachment_from_disk(instances, path, requester, "pack action") @classmethod @transition_action( return_attachment=True, - verbose_name='Go to post office', - run_after=['pack'], + verbose_name="Go to post office", + run_after=["pack"], ) def go_to_post_office(cls, instances, **kwargs): pass @@ -100,18 +93,16 @@ def go_to_post_office(cls, instances, **kwargs): return_attachment=False, ) def generate_exception(cls, instances, request, **kwargs): - raise Exception('exception') + raise Exception("exception") @transition_action(model=Order) def action_registered_on_model(cls, *args, **kwargs): - for instance in kwargs['instances']: - instance.remarks = 'done' + for instance in kwargs["instances"]: + instance.remarks = "done" -class AsyncOrder( - AdminAbsoluteUrlMixin, models.Model, metaclass=TransitionWorkflowBase -): +class AsyncOrder(AdminAbsoluteUrlMixin, models.Model, metaclass=TransitionWorkflowBase): status = TransitionField( default=OrderStatus.new.id, choices=OrderStatus(), @@ -123,49 +114,46 @@ class AsyncOrder( @classmethod @transition_action( - verbose_name='Long running action', + verbose_name="Long running action", form_fields={ - 'name': { - 'field': forms.CharField(label='name'), + "name": { + "field": forms.CharField(label="name"), } }, is_async=True, - run_after=['freezing_action'] + run_after=["freezing_action"], ) def long_running_action(cls, instances, **kwargs): for instance in instances: instance.counter += 1 - instance.name = kwargs['name'] + instance.name = kwargs["name"] instance.save() @classmethod @transition_action( - verbose_name='Another long running action', + verbose_name="Another long running action", form_fields={ - 'foo': { - 'field': forms.CharField(label='Foo'), - 'autocomplete_field': 'foo', + "foo": { + "field": forms.CharField(label="Foo"), + "autocomplete_field": "foo", } }, is_async=True, - run_after=['long_running_action'] + run_after=["long_running_action"], ) def long_running_action_with_precondition(cls, instances, **kwargs): instance = instances[0] # only one instance in asyc action instance.counter += 1 instance.save() - kwargs['shared_params'][instance.pk]['counter'] = instance.counter - kwargs['history_kwargs'][instance.pk]['hist_counter'] = instance.counter + kwargs["shared_params"][instance.pk]["counter"] = instance.counter + kwargs["history_kwargs"][instance.pk]["hist_counter"] = instance.counter if instance.counter < 5: raise RescheduleAsyncTransitionActionLater() - instance.foo = kwargs['foo'] + instance.foo = kwargs["foo"] instance.save() @classmethod - @transition_action( - verbose_name='Assign user', - run_after=['long_running_action'] - ) + @transition_action(verbose_name="Assign user", run_after=["long_running_action"]) def assing_user(cls, instances, requester, **kwargs): for instance in instances: instance.username = requester.username @@ -173,20 +161,20 @@ def assing_user(cls, instances, requester, **kwargs): @classmethod @transition_action( - verbose_name='Failing action', + verbose_name="Failing action", is_async=True, ) def failing_action(cls, instances, **kwargs): - kwargs['shared_params'][instances[0].pk]['test'] = 'failing' + kwargs["shared_params"][instances[0].pk]["test"] = "failing" raise ValueError() @classmethod @transition_action( - verbose_name='Freezing action', + verbose_name="Freezing action", is_async=True, ) def freezing_action(cls, instances, **kwargs): - kwargs['shared_params'][instances[0].pk]['test'] = 'freezing' + kwargs["shared_params"][instances[0].pk]["test"] = "freezing" raise FreezeAsyncTransition() @@ -194,18 +182,19 @@ class TestAsset(models.Model): hostname = models.CharField(max_length=50) sn = models.CharField(max_length=200, null=True, blank=True, unique=True) barcode = models.CharField( - max_length=200, null=True, blank=True, unique=True, default=None, + max_length=200, + null=True, + blank=True, + unique=True, + default=None, ) class BaseObjectForeignKeyModel(models.Model): base_object = BaseObjectForeignKey( BaseObject, - limit_models=[ - 'back_office.BackOfficeAsset', - 'data_center.DataCenterAsset' - ], - on_delete=models.CASCADE + limit_models=["back_office.BackOfficeAsset", "data_center.DataCenterAsset"], + on_delete=models.CASCADE, ) diff --git a/src/ralph/trade_marks/admin.py b/src/ralph/trade_marks/admin.py index 1da56f0073..2fcd6454d8 100644 --- a/src/ralph/trade_marks/admin.py +++ b/src/ralph/trade_marks/admin.py @@ -8,7 +8,7 @@ ChoicesListFilter, custom_title_filter, DateListFilter, - RelatedAutocompleteFieldListFilter + RelatedAutocompleteFieldListFilter, ) from ralph.admin.mixins import RalphAdmin, RalphTabularInline from ralph.admin.views.extra import RalphDetailViewAdmin @@ -17,7 +17,7 @@ DesignForm, PatentForm, TradeMarkForm, - UtilityModelForm + UtilityModelForm, ) from ralph.trade_marks.models import ( Design, @@ -35,130 +35,139 @@ TradeMarksLinkedDomains, UtilityModel, UtilityModelAdditionalCountry, - UtilityModelLinkedDomains + UtilityModelLinkedDomains, ) class IntellectualPropertyLinkedDomainViewBase(RalphDetailViewAdmin): - icon = 'table' - name = 'table' - label = _('Assigned to domain') - url_name = 'assigned-to-domain' + icon = "table" + name = "table" + label = _("Assigned to domain") + url_name = "assigned-to-domain" class TradeMarksLinkedDomainsView(IntellectualPropertyLinkedDomainViewBase): - class Inline(RalphTabularInline): model = TradeMarksLinkedDomains - raw_id_fields = ('domain', admin.RelatedFieldListFilter) + raw_id_fields = ("domain", admin.RelatedFieldListFilter) extra = 1 inlines = [Inline] class DesignLinkedDomainsView(IntellectualPropertyLinkedDomainViewBase): - class Inline(RalphTabularInline): model = DesignsLinkedDomains - raw_id_fields = ('domain', admin.RelatedFieldListFilter) + raw_id_fields = ("domain", admin.RelatedFieldListFilter) extra = 1 inlines = [Inline] class PatentLinkedDomainsView(IntellectualPropertyLinkedDomainViewBase): - class Inline(RalphTabularInline): model = PatentsLinkedDomains - raw_id_fields = ('domain', admin.RelatedFieldListFilter) + raw_id_fields = ("domain", admin.RelatedFieldListFilter) extra = 1 inlines = [Inline] class UtilityModelLinkedDomainsView(IntellectualPropertyLinkedDomainViewBase): - class Inline(RalphTabularInline): model = UtilityModelLinkedDomains - raw_id_fields = ('domain', admin.RelatedFieldListFilter) + raw_id_fields = ("domain", admin.RelatedFieldListFilter) extra = 1 inlines = [Inline] class IntellectualPropertyAdminBase(AttachmentsMixin, RalphAdmin): - - search_fields = ['name', 'id', ] - readonly_fields = ['image_tag'] + search_fields = [ + "name", + "id", + ] + readonly_fields = ["image_tag"] list_select_related = [ - 'technical_owner', 'business_owner', 'holder', + "technical_owner", + "business_owner", + "holder", ] list_filter = [ - 'number', - ('valid_from', DateListFilter), - ('valid_to', DateListFilter), - 'additional_markings', - 'holder', - 'status', + "number", + ("valid_from", DateListFilter), + ("valid_to", DateListFilter), + "additional_markings", + "holder", + "status", ] list_display = [ - 'number', 'region', 'name', 'classes', - 'valid_from', 'valid_to', 'status', 'holder', 'representation', - 'get_database_link' - ] - raw_id_fields = [ - 'business_owner', 'technical_owner', 'holder' + "number", + "region", + "name", + "classes", + "valid_from", + "valid_to", + "status", + "holder", + "representation", + "get_database_link", ] + raw_id_fields = ["business_owner", "technical_owner", "holder"] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', 'database_link', 'number', 'image', 'image_tag', - 'classes', 'valid_from', 'valid_to', - 'registrar_institution', 'order_number_url', - 'additional_markings', 'holder', 'status', 'remarks' - ) - }), - (_('Ownership info'), { - 'fields': ( - 'business_owner', 'technical_owner' - ) - }) + ( + _("Basic info"), + { + "fields": ( + "name", + "database_link", + "number", + "image", + "image_tag", + "classes", + "valid_from", + "valid_to", + "registrar_institution", + "order_number_url", + "additional_markings", + "holder", + "status", + "remarks", + ) + }, + ), + (_("Ownership info"), {"fields": ("business_owner", "technical_owner")}), ) def get_database_link(self, obj): if obj.database_link: return mark_safe( - 'link'.format( - obj.database_link - ) + 'link'.format(obj.database_link) ) else: - return '-' + return "-" - get_database_link.short_description = _('Database link') + get_database_link.short_description = _("Database link") def representation(self, obj): if obj.image: return self.image_tag(obj) else: - return '-' + return "-" def image_tag(self, obj): if not obj.image: return "" - return mark_safe( - ''.format(obj.image.url) - ) + return mark_safe(''.format(obj.image.url)) - image_tag.short_description = _('Image') + image_tag.short_description = _("Image") @register(TradeMark) class TradeMarkAdmin(IntellectualPropertyAdminBase): - class TypeFilter(ChoicesListFilter): - title = 'Trade Mark type' - parameter_name = 'type' + title = "Trade Mark type" + parameter_name = "type" @property def _choices_list(self): @@ -176,87 +185,100 @@ def queryset(self, request, queryset): change_views = [TradeMarksLinkedDomainsView] form = TradeMarkForm list_filter = [ - 'number', - ('type', TypeFilter), - ('valid_from', DateListFilter), - ('valid_to', DateListFilter), - 'additional_markings', - 'holder', - 'status', + "number", + ("type", TypeFilter), + ("valid_from", DateListFilter), + ("valid_to", DateListFilter), + "additional_markings", + "holder", + "status", ( - 'trademarkadditionalcountry__country', - custom_title_filter('Region', RelatedAutocompleteFieldListFilter) - ) + "trademarkadditionalcountry__country", + custom_title_filter("Region", RelatedAutocompleteFieldListFilter), + ), ] fieldsets = ( - (_('Basic info'), { - 'fields': ( - 'name', 'database_link', 'number', 'type', 'image', 'image_tag', - 'classes', 'valid_from', 'valid_to', - 'registrar_institution', 'order_number_url', - 'additional_markings', 'holder', 'status', 'remarks' - ) - }), - (_('Ownership info'), { - 'fields': ( - 'business_owner', 'technical_owner' - ) - }) + ( + _("Basic info"), + { + "fields": ( + "name", + "database_link", + "number", + "type", + "image", + "image_tag", + "classes", + "valid_from", + "valid_to", + "registrar_institution", + "order_number_url", + "additional_markings", + "holder", + "status", + "remarks", + ) + }, + ), + (_("Ownership info"), {"fields": ("business_owner", "technical_owner")}), ) def region(self, obj): - return ', '.join( - tm_country.country.name for tm_country in - obj.trademarkadditionalcountry_set.all() + return ", ".join( + tm_country.country.name + for tm_country in obj.trademarkadditionalcountry_set.all() ) def get_queryset(self, request): - return super().get_queryset(request).prefetch_related( - 'trademarkadditionalcountry_set__country' + return ( + super() + .get_queryset(request) + .prefetch_related("trademarkadditionalcountry_set__country") ) class AdditionalCountryInline(RalphTabularInline): model = TradeMarkAdditionalCountry extra = 1 - verbose_name = _('country') + verbose_name = _("country") inlines = [AdditionalCountryInline] @register(Design) class DesignAdmin(IntellectualPropertyAdminBase): - change_views = [DesignLinkedDomainsView] form = DesignForm list_filter = [ - 'number', - ('valid_from', DateListFilter), - ('valid_to', DateListFilter), - 'additional_markings', - 'holder', - 'status', + "number", + ("valid_from", DateListFilter), + ("valid_to", DateListFilter), + "additional_markings", + "holder", + "status", ( - 'designadditionalcountry__country', - custom_title_filter('Region', RelatedAutocompleteFieldListFilter) - ) + "designadditionalcountry__country", + custom_title_filter("Region", RelatedAutocompleteFieldListFilter), + ), ] def region(self, obj): - return ', '.join( - tm_country.country.name for tm_country in - obj.designadditionalcountry_set.all() + return ", ".join( + tm_country.country.name + for tm_country in obj.designadditionalcountry_set.all() ) def get_queryset(self, request): - return super().get_queryset(request).prefetch_related( - 'designadditionalcountry_set__country' + return ( + super() + .get_queryset(request) + .prefetch_related("designadditionalcountry_set__country") ) class AdditionalCountryInline(RalphTabularInline): model = DesignAdditionalCountry extra = 1 - verbose_name = _('country') + verbose_name = _("country") inlines = [AdditionalCountryInline] @@ -266,33 +288,35 @@ class PatentAdmin(IntellectualPropertyAdminBase): change_views = [PatentLinkedDomainsView] form = PatentForm list_filter = [ - 'number', - ('valid_from', DateListFilter), - ('valid_to', DateListFilter), - 'additional_markings', - 'holder', - 'status', + "number", + ("valid_from", DateListFilter), + ("valid_to", DateListFilter), + "additional_markings", + "holder", + "status", ( - 'patentadditionalcountry__country', - custom_title_filter('Region', RelatedAutocompleteFieldListFilter) - ) + "patentadditionalcountry__country", + custom_title_filter("Region", RelatedAutocompleteFieldListFilter), + ), ] def region(self, obj): - return ', '.join( - tm_country.country.name for tm_country in - obj.patentadditionalcountry_set.all() + return ", ".join( + tm_country.country.name + for tm_country in obj.patentadditionalcountry_set.all() ) def get_queryset(self, request): - return super().get_queryset(request).prefetch_related( - 'patentadditionalcountry_set__country' + return ( + super() + .get_queryset(request) + .prefetch_related("patentadditionalcountry_set__country") ) class AdditionalCountryInline(RalphTabularInline): model = PatentAdditionalCountry extra = 1 - verbose_name = _('country') + verbose_name = _("country") inlines = [AdditionalCountryInline] @@ -304,8 +328,7 @@ class ProviderAdditionalMarkingAdmin(RalphAdmin): @register(TradeMarkRegistrarInstitution) class TradeMarkRegistrarInstitutionAdmin(RalphAdmin): - - search_fields = ['name'] + search_fields = ["name"] @register(TradeMarkCountry) @@ -318,32 +341,34 @@ class UtilityModelAdmin(IntellectualPropertyAdminBase): change_views = [UtilityModelLinkedDomainsView] form = UtilityModelForm list_filter = [ - 'number', - ('valid_from', DateListFilter), - ('valid_to', DateListFilter), - 'additional_markings', - 'holder', - 'status', + "number", + ("valid_from", DateListFilter), + ("valid_to", DateListFilter), + "additional_markings", + "holder", + "status", ( - 'utilitymodeladditionalcountry__country', - custom_title_filter('Region', RelatedAutocompleteFieldListFilter) - ) + "utilitymodeladditionalcountry__country", + custom_title_filter("Region", RelatedAutocompleteFieldListFilter), + ), ] def region(self, obj): - return ', '.join( - tm_country.country.name for tm_country in - obj.utilitymodeladditionalcountry_set.all() + return ", ".join( + tm_country.country.name + for tm_country in obj.utilitymodeladditionalcountry_set.all() ) def get_queryset(self, request): - return super().get_queryset(request).prefetch_related( - 'utilitymodeladditionalcountry_set__country' + return ( + super() + .get_queryset(request) + .prefetch_related("utilitymodeladditionalcountry_set__country") ) class AdditionalCountryInline(RalphTabularInline): model = UtilityModelAdditionalCountry extra = 1 - verbose_name = _('country') + verbose_name = _("country") inlines = [AdditionalCountryInline] diff --git a/src/ralph/trade_marks/forms.py b/src/ralph/trade_marks/forms.py index 43f73b5b25..4efa308ece 100644 --- a/src/ralph/trade_marks/forms.py +++ b/src/ralph/trade_marks/forms.py @@ -6,9 +6,9 @@ class IntellectualPropertyForm(RalphAdminForm): class Meta: - fields = ['additional_markings'] + fields = ["additional_markings"] widgets = { - 'additional_markings': CheckboxSelectMultiple, + "additional_markings": CheckboxSelectMultiple, } diff --git a/src/ralph/trade_marks/migrations/0001_initial.py b/src/ralph/trade_marks/migrations/0001_initial.py index 165cd4ec69..fe3923c22c 100644 --- a/src/ralph/trade_marks/migrations/0001_initial.py +++ b/src/ralph/trade_marks/migrations/0001_initial.py @@ -8,78 +8,197 @@ class Migration(migrations.Migration): - dependencies = [ - ('domains', '0006_auto_20180725_1216'), - ('assets', '0027_asset_buyout_date'), - ('accounts', '0006_remove_ralphuser_gender'), + ("domains", "0006_auto_20180725_1216"), + ("assets", "0027_asset_buyout_date"), + ("accounts", "0006_remove_ralphuser_gender"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='ProviderAdditionalMarking', + name="ProviderAdditionalMarking", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(unique=True, verbose_name='name', max_length=255)), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(unique=True, verbose_name="name", max_length=255), + ), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), ], options={ - 'abstract': False, - 'ordering': ['name'], + "abstract": False, + "ordering": ["name"], }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='TradeMark', + name="TradeMark", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, serialize=False, parent_link=True, auto_created=True, to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(verbose_name='Trade Mark name', max_length=255)), - ('registrant_number', models.CharField(verbose_name='Registrant number', max_length=255)), - ('type', models.PositiveIntegerField(verbose_name='Trade Mark type', choices=[(1, 'Word'), (2, 'Figurative'), (3, 'Word - Figurative')], default=2)), - ('registrant_class', models.CharField(verbose_name='Registrant class', max_length=255)), - ('valid_to', models.DateField()), - ('order_number_url', models.URLField(null=True, blank=True, max_length=255)), - ('status', models.PositiveIntegerField(verbose_name='Trade Mark status', choices=[(1, 'Application filed'), (2, 'Application refused'), (3, 'Application withdrawn'), (4, 'Application opposed'), (5, 'Registered'), (6, 'Registration invalidated'), (7, 'Registration expired')], default=5)), - ('additional_markings', models.ManyToManyField(blank=True, to='trade_marks.ProviderAdditionalMarking')), - ('business_owner', models.ForeignKey(related_name='trademark_business_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + serialize=False, + parent_link=True, + auto_created=True, + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "name", + models.CharField(verbose_name="Trade Mark name", max_length=255), + ), + ( + "registrant_number", + models.CharField(verbose_name="Registrant number", max_length=255), + ), + ( + "type", + models.PositiveIntegerField( + verbose_name="Trade Mark type", + choices=[ + (1, "Word"), + (2, "Figurative"), + (3, "Word - Figurative"), + ], + default=2, + ), + ), + ( + "registrant_class", + models.CharField(verbose_name="Registrant class", max_length=255), + ), + ("valid_to", models.DateField()), + ( + "order_number_url", + models.URLField(null=True, blank=True, max_length=255), + ), + ( + "status", + models.PositiveIntegerField( + verbose_name="Trade Mark status", + choices=[ + (1, "Application filed"), + (2, "Application refused"), + (3, "Application withdrawn"), + (4, "Application opposed"), + (5, "Registered"), + (6, "Registration invalidated"), + (7, "Registration expired"), + ], + default=5, + ), + ), + ( + "additional_markings", + models.ManyToManyField( + blank=True, to="trade_marks.ProviderAdditionalMarking" + ), + ), + ( + "business_owner", + models.ForeignKey( + related_name="trademark_business_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject', models.Model), + bases=( + ralph.lib.mixins.models.AdminAbsoluteUrlMixin, + "assets.baseobject", + models.Model, + ), ), migrations.CreateModel( - name='TradeMarksLinkedDomains', + name="TradeMarksLinkedDomains", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('domain', models.ForeignKey(related_name='trade_mark', to='domains.Domain', on_delete=django.db.models.deletion.CASCADE)), - ('trade_mark', models.ForeignKey(to='trade_marks.TradeMark', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "domain", + models.ForeignKey( + related_name="trade_mark", + to="domains.Domain", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "trade_mark", + models.ForeignKey( + to="trade_marks.TradeMark", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], ), migrations.AddField( - model_name='trademark', - name='domains', - field=models.ManyToManyField(related_name='_trademark_domains_+', through='trade_marks.TradeMarksLinkedDomains', to='domains.Domain'), + model_name="trademark", + name="domains", + field=models.ManyToManyField( + related_name="_trademark_domains_+", + through="trade_marks.TradeMarksLinkedDomains", + to="domains.Domain", + ), ), migrations.AddField( - model_name='trademark', - name='holder', - field=models.ForeignKey(to='assets.AssetHolder', verbose_name='Trade Mark holder', null=True, blank=True, on_delete=django.db.models.deletion.CASCADE), + model_name="trademark", + name="holder", + field=models.ForeignKey( + to="assets.AssetHolder", + verbose_name="Trade Mark holder", + null=True, + blank=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='trademark', - name='region', - field=models.ForeignKey(to='accounts.Region', on_delete=django.db.models.deletion.CASCADE), + model_name="trademark", + name="region", + field=models.ForeignKey( + to="accounts.Region", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AddField( - model_name='trademark', - name='technical_owner', - field=models.ForeignKey(related_name='trademark_technical_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE), + model_name="trademark", + name="technical_owner", + field=models.ForeignKey( + related_name="trademark_technical_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterUniqueTogether( - name='trademarkslinkeddomains', - unique_together=set([('trade_mark', 'domain')]), + name="trademarkslinkeddomains", + unique_together=set([("trade_mark", "domain")]), ), ] diff --git a/src/ralph/trade_marks/migrations/0002_auto_20181005_1446.py b/src/ralph/trade_marks/migrations/0002_auto_20181005_1446.py index 5c2b9be787..8497e1b7a5 100644 --- a/src/ralph/trade_marks/migrations/0002_auto_20181005_1446.py +++ b/src/ralph/trade_marks/migrations/0002_auto_20181005_1446.py @@ -1,18 +1,20 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0001_initial'), + ("trade_marks", "0001_initial"), ] operations = [ migrations.AlterModelOptions( - name='trademarkslinkeddomains', - options={'verbose_name': 'Trade Marks Linked Domain', 'verbose_name_plural': 'Trade Marks Linked Domains'}, + name="trademarkslinkeddomains", + options={ + "verbose_name": "Trade Marks Linked Domain", + "verbose_name_plural": "Trade Marks Linked Domains", + }, ), ] diff --git a/src/ralph/trade_marks/migrations/0003_trademark_image.py b/src/ralph/trade_marks/migrations/0003_trademark_image.py index cea1b901fe..2de8c930dc 100644 --- a/src/ralph/trade_marks/migrations/0003_trademark_image.py +++ b/src/ralph/trade_marks/migrations/0003_trademark_image.py @@ -6,15 +6,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0002_auto_20181005_1446'), + ("trade_marks", "0002_auto_20181005_1446"), ] operations = [ migrations.AddField( - model_name='trademark', - name='image', - field=models.ImageField(null=True, upload_to=ralph.trade_marks.models.upload_dir, blank=True), + model_name="trademark", + name="image", + field=models.ImageField( + null=True, upload_to=ralph.trade_marks.models.upload_dir, blank=True + ), ), ] diff --git a/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py b/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py index 6b309e3b12..9a1b8f3b5e 100644 --- a/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py +++ b/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py @@ -7,65 +7,350 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0003_trademark_image'), + ("trade_marks", "0003_trademark_image"), ] operations = [ migrations.CreateModel( - name='TradeMarkAdditionalCountry', + name="TradeMarkAdditionalCountry", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), ], options={ - 'verbose_name_plural': 'Trade Mark Additional Countries', - 'verbose_name': 'Trade Mark Additional Country', + "verbose_name_plural": "Trade Mark Additional Countries", + "verbose_name": "Trade Mark Additional Country", }, ), migrations.CreateModel( - name='TradeMarkCountry', + name="TradeMarkCountry", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('country', models.PositiveIntegerField(choices=[(1, 'Afghanistan'), (2, 'Albania'), (3, 'Algeria'), (4, 'American Samoa'), (5, 'Andorra'), (6, 'Angola'), (7, 'Anguilla'), (8, 'Antarctica'), (9, 'Antigua and Barbuda'), (10, 'Argentina'), (11, 'Armenia'), (12, 'Aruba'), (13, 'Australia'), (14, 'Austria'), (15, 'Azerbaijan'), (16, 'Bahamas'), (17, 'Bahrain'), (18, 'Bangladesh'), (19, 'Barbados'), (20, 'Belarus'), (21, 'Belgium'), (22, 'Belize'), (23, 'Benin'), (24, 'Bermuda'), (25, 'Bhutan'), (26, 'Bolivia'), (27, 'Bosnia and Herzegovina'), (28, 'Botswana'), (29, 'Brazil'), (30, 'Brunei'), (31, 'Bulgaria'), (32, 'Burkina Faso'), (33, 'Burundi'), (34, 'Cambodia'), (35, 'Cameroon'), (36, 'Canada'), (37, 'Cape Verde'), (38, 'Cayman Islands'), (39, 'Central African Republic'), (40, 'Chad'), (41, 'Chile'), (42, 'China'), (43, 'Colombia'), (44, 'Comoros'), (45, 'Congo Brazzaville'), (46, 'Congo Kinshasa'), (47, 'Cook Islands'), (48, 'Costa Rica'), (49, 'Cote Divoire'), (50, 'Croatia'), (51, 'Cuba'), (52, 'Cyprus'), (53, 'Czech Republic'), (54, 'Denmark'), (55, 'Djibouti'), (56, 'Dominica'), (57, 'Dominican Republic'), (58, 'Ecuador'), (59, 'Egypt'), (60, 'El Salvador'), (61, 'Equatorial Guinea'), (62, 'Eritrea'), (63, 'Estonia'), (64, 'Ethiopia'), (65, 'Faroe Islands'), (66, 'Fiji'), (67, 'Finland'), (68, 'France'), (69, 'French Polynesia'), (70, 'Gabon'), (71, 'Gambia'), (72, 'Georgia'), (73, 'Germany'), (74, 'Ghana'), (75, 'Gibraltar'), (76, 'Greece'), (77, 'Grenada'), (78, 'Guam'), (79, 'Guatemala'), (80, 'Guinea Bissau'), (81, 'Guinea'), (82, 'Guyana'), (83, 'Haiti'), (84, 'Honduras'), (85, 'Hong Kong'), (86, 'Hungary'), (87, 'Iceland'), (88, 'India'), (89, 'Indonesia'), (90, 'Iran'), (91, 'Iraq'), (92, 'Ireland'), (93, 'Israel'), (94, 'Italy'), (95, 'Jamaica'), (96, 'Japan'), (97, 'Jersey'), (98, 'Jordan'), (99, 'Kazakhstan'), (100, 'Kenya'), (101, 'Kiribati'), (102, 'Kuwait'), (103, 'Kyrgyzstan'), (104, 'Laos'), (105, 'Latvia'), (106, 'Lebanon'), (107, 'Lesotho'), (108, 'Liberia'), (109, 'Libya'), (110, 'Liechtenstein'), (111, 'Lithuania'), (112, 'Luxembourg'), (113, 'Macau'), (114, 'Macedonia'), (115, 'Madagascar'), (116, 'Malawi'), (117, 'Malaysia'), (118, 'Maldives'), (119, 'Mali'), (120, 'Malta'), (121, 'Marshall Islands'), (122, 'Mauritania'), (123, 'Mauritius'), (124, 'Mexico'), (125, 'Micronesia'), (126, 'Moldova'), (127, 'Monaco'), (128, 'Mongolia'), (129, 'Montenegro'), (130, 'Montserrat'), (131, 'Morocco'), (132, 'Mozambique'), (133, 'Myanmar'), (134, 'Namibia'), (135, 'Nauru'), (136, 'Nepal'), (137, 'Netherlands Antilles'), (138, 'Netherlands'), (139, 'New Zealand'), (140, 'Nicaragua'), (141, 'Niger'), (142, 'Nigeria'), (143, 'North Korea'), (144, 'Norway'), (145, 'Oman'), (146, 'Pakistan'), (147, 'Palau'), (148, 'Panama'), (149, 'Papua New Guinea'), (150, 'Paraguay'), (151, 'Peru'), (152, 'Philippines'), (153, 'Poland'), (154, 'Portugal'), (155, 'Puerto Rico'), (156, 'Qatar'), (157, 'Romania'), (158, 'Russian Federation'), (159, 'Rwanda'), (160, 'Saint Lucia'), (161, 'Samoa'), (162, 'San Marino'), (163, 'Sao Tome and Principe'), (164, 'Saudi Arabia'), (165, 'Senegal'), (166, 'Serbia'), (167, 'Seychelles'), (168, 'Sierra Leone'), (169, 'Singapore'), (170, 'Slovakia'), (171, 'Slovenia'), (172, 'Solomon Islands'), (173, 'Somalia'), (174, 'South Africa'), (175, 'South Korea'), (176, 'Spain'), (177, 'Sri Lanka'), (178, 'St Kitts and Nevis'), (179, 'St Vincent and the Grenadines'), (180, 'Sudan'), (181, 'Suriname'), (182, 'Swaziland'), (183, 'Sweden'), (184, 'Switzerland'), (185, 'Syria'), (186, 'Tajikistan'), (187, 'Taiwan'), (188, 'Tanzania'), (189, 'Thailand'), (190, 'Timor Leste'), (191, 'Togo'), (192, 'Tonga'), (193, 'Trinidad and Tobago'), (194, 'Tunisia'), (195, 'Turkey'), (196, 'Turkmenistan'), (197, 'Turks and Caicos Islands'), (198, 'Tuvalu'), (199, 'Uganda'), (200, 'Ukraine'), (201, 'United Arab Emirates'), (202, 'United Kingdom'), (203, 'United States of America'), (204, 'Uruguay'), (205, 'Uzbekistan'), (206, 'Vanuatu'), (207, 'Vatican City'), (208, 'Venezuela'), (209, 'Viet Nam'), (210, 'Virgin Islands British'), (211, 'Virgin Islands US'), (212, 'Western Sahara'), (213, 'Yemen'), (214, 'Zambia'), (215, 'Zimbabwe'), (301, 'England'), (302, 'Northern Ireland'), (303, 'Wales'), (304, 'Scotland'), (601, 'Northern Cyprus'), (602, 'Palestine'), (603, 'Somaliland'), (901, 'African Union'), (902, 'Arab League'), (903, 'Association of Southeast Asian Nations'), (904, 'Caricom'), (905, 'Commonwealth of Independent States'), (906, 'Commonwealth of Nations'), (907, 'European Union'), (908, 'Islamic Conference'), (909, 'NATO'), (910, 'Olimpic Movement'), (911, 'OPEC'), (912, 'Red Cross'), (913, 'United Nations')], default=153, blank=True, verbose_name='trade_mark_country', null=True)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ( + "country", + models.PositiveIntegerField( + choices=[ + (1, "Afghanistan"), + (2, "Albania"), + (3, "Algeria"), + (4, "American Samoa"), + (5, "Andorra"), + (6, "Angola"), + (7, "Anguilla"), + (8, "Antarctica"), + (9, "Antigua and Barbuda"), + (10, "Argentina"), + (11, "Armenia"), + (12, "Aruba"), + (13, "Australia"), + (14, "Austria"), + (15, "Azerbaijan"), + (16, "Bahamas"), + (17, "Bahrain"), + (18, "Bangladesh"), + (19, "Barbados"), + (20, "Belarus"), + (21, "Belgium"), + (22, "Belize"), + (23, "Benin"), + (24, "Bermuda"), + (25, "Bhutan"), + (26, "Bolivia"), + (27, "Bosnia and Herzegovina"), + (28, "Botswana"), + (29, "Brazil"), + (30, "Brunei"), + (31, "Bulgaria"), + (32, "Burkina Faso"), + (33, "Burundi"), + (34, "Cambodia"), + (35, "Cameroon"), + (36, "Canada"), + (37, "Cape Verde"), + (38, "Cayman Islands"), + (39, "Central African Republic"), + (40, "Chad"), + (41, "Chile"), + (42, "China"), + (43, "Colombia"), + (44, "Comoros"), + (45, "Congo Brazzaville"), + (46, "Congo Kinshasa"), + (47, "Cook Islands"), + (48, "Costa Rica"), + (49, "Cote Divoire"), + (50, "Croatia"), + (51, "Cuba"), + (52, "Cyprus"), + (53, "Czech Republic"), + (54, "Denmark"), + (55, "Djibouti"), + (56, "Dominica"), + (57, "Dominican Republic"), + (58, "Ecuador"), + (59, "Egypt"), + (60, "El Salvador"), + (61, "Equatorial Guinea"), + (62, "Eritrea"), + (63, "Estonia"), + (64, "Ethiopia"), + (65, "Faroe Islands"), + (66, "Fiji"), + (67, "Finland"), + (68, "France"), + (69, "French Polynesia"), + (70, "Gabon"), + (71, "Gambia"), + (72, "Georgia"), + (73, "Germany"), + (74, "Ghana"), + (75, "Gibraltar"), + (76, "Greece"), + (77, "Grenada"), + (78, "Guam"), + (79, "Guatemala"), + (80, "Guinea Bissau"), + (81, "Guinea"), + (82, "Guyana"), + (83, "Haiti"), + (84, "Honduras"), + (85, "Hong Kong"), + (86, "Hungary"), + (87, "Iceland"), + (88, "India"), + (89, "Indonesia"), + (90, "Iran"), + (91, "Iraq"), + (92, "Ireland"), + (93, "Israel"), + (94, "Italy"), + (95, "Jamaica"), + (96, "Japan"), + (97, "Jersey"), + (98, "Jordan"), + (99, "Kazakhstan"), + (100, "Kenya"), + (101, "Kiribati"), + (102, "Kuwait"), + (103, "Kyrgyzstan"), + (104, "Laos"), + (105, "Latvia"), + (106, "Lebanon"), + (107, "Lesotho"), + (108, "Liberia"), + (109, "Libya"), + (110, "Liechtenstein"), + (111, "Lithuania"), + (112, "Luxembourg"), + (113, "Macau"), + (114, "Macedonia"), + (115, "Madagascar"), + (116, "Malawi"), + (117, "Malaysia"), + (118, "Maldives"), + (119, "Mali"), + (120, "Malta"), + (121, "Marshall Islands"), + (122, "Mauritania"), + (123, "Mauritius"), + (124, "Mexico"), + (125, "Micronesia"), + (126, "Moldova"), + (127, "Monaco"), + (128, "Mongolia"), + (129, "Montenegro"), + (130, "Montserrat"), + (131, "Morocco"), + (132, "Mozambique"), + (133, "Myanmar"), + (134, "Namibia"), + (135, "Nauru"), + (136, "Nepal"), + (137, "Netherlands Antilles"), + (138, "Netherlands"), + (139, "New Zealand"), + (140, "Nicaragua"), + (141, "Niger"), + (142, "Nigeria"), + (143, "North Korea"), + (144, "Norway"), + (145, "Oman"), + (146, "Pakistan"), + (147, "Palau"), + (148, "Panama"), + (149, "Papua New Guinea"), + (150, "Paraguay"), + (151, "Peru"), + (152, "Philippines"), + (153, "Poland"), + (154, "Portugal"), + (155, "Puerto Rico"), + (156, "Qatar"), + (157, "Romania"), + (158, "Russian Federation"), + (159, "Rwanda"), + (160, "Saint Lucia"), + (161, "Samoa"), + (162, "San Marino"), + (163, "Sao Tome and Principe"), + (164, "Saudi Arabia"), + (165, "Senegal"), + (166, "Serbia"), + (167, "Seychelles"), + (168, "Sierra Leone"), + (169, "Singapore"), + (170, "Slovakia"), + (171, "Slovenia"), + (172, "Solomon Islands"), + (173, "Somalia"), + (174, "South Africa"), + (175, "South Korea"), + (176, "Spain"), + (177, "Sri Lanka"), + (178, "St Kitts and Nevis"), + (179, "St Vincent and the Grenadines"), + (180, "Sudan"), + (181, "Suriname"), + (182, "Swaziland"), + (183, "Sweden"), + (184, "Switzerland"), + (185, "Syria"), + (186, "Tajikistan"), + (187, "Taiwan"), + (188, "Tanzania"), + (189, "Thailand"), + (190, "Timor Leste"), + (191, "Togo"), + (192, "Tonga"), + (193, "Trinidad and Tobago"), + (194, "Tunisia"), + (195, "Turkey"), + (196, "Turkmenistan"), + (197, "Turks and Caicos Islands"), + (198, "Tuvalu"), + (199, "Uganda"), + (200, "Ukraine"), + (201, "United Arab Emirates"), + (202, "United Kingdom"), + (203, "United States of America"), + (204, "Uruguay"), + (205, "Uzbekistan"), + (206, "Vanuatu"), + (207, "Vatican City"), + (208, "Venezuela"), + (209, "Viet Nam"), + (210, "Virgin Islands British"), + (211, "Virgin Islands US"), + (212, "Western Sahara"), + (213, "Yemen"), + (214, "Zambia"), + (215, "Zimbabwe"), + (301, "England"), + (302, "Northern Ireland"), + (303, "Wales"), + (304, "Scotland"), + (601, "Northern Cyprus"), + (602, "Palestine"), + (603, "Somaliland"), + (901, "African Union"), + (902, "Arab League"), + (903, "Association of Southeast Asian Nations"), + (904, "Caricom"), + (905, "Commonwealth of Independent States"), + (906, "Commonwealth of Nations"), + (907, "European Union"), + (908, "Islamic Conference"), + (909, "NATO"), + (910, "Olimpic Movement"), + (911, "OPEC"), + (912, "Red Cross"), + (913, "United Nations"), + ], + default=153, + blank=True, + verbose_name="trade_mark_country", + null=True, + ), + ), ], bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.CreateModel( - name='TradeMarkRegistrarInstitution', + name="TradeMarkRegistrarInstitution", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('name', models.CharField(max_length=75, verbose_name='name')), - ('created', models.DateTimeField(verbose_name='date created', auto_now_add=True)), - ('modified', models.DateTimeField(verbose_name='last modified', auto_now=True)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=75, verbose_name="name")), + ( + "created", + models.DateTimeField( + verbose_name="date created", auto_now_add=True + ), + ), + ( + "modified", + models.DateTimeField(verbose_name="last modified", auto_now=True), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), migrations.RemoveField( - model_name='trademark', - name='region', + model_name="trademark", + name="region", ), migrations.AddField( - model_name='trademarkadditionalcountry', - name='country', - field=models.ForeignKey(to='trade_marks.TradeMarkCountry', on_delete=django.db.models.deletion.CASCADE), + model_name="trademarkadditionalcountry", + name="country", + field=models.ForeignKey( + to="trade_marks.TradeMarkCountry", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='trademarkadditionalcountry', - name='trade_mark', - field=models.ForeignKey(to='trade_marks.TradeMark', on_delete=django.db.models.deletion.CASCADE), + model_name="trademarkadditionalcountry", + name="trade_mark", + field=models.ForeignKey( + to="trade_marks.TradeMark", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AddField( - model_name='trademark', - name='registrar_institution', - field=models.ForeignKey(to='trade_marks.TradeMarkRegistrarInstitution', null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="trademark", + name="registrar_institution", + field=models.ForeignKey( + to="trade_marks.TradeMarkRegistrarInstitution", + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterUniqueTogether( - name='trademarkadditionalcountry', - unique_together=set([('country', 'trade_mark')]), + name="trademarkadditionalcountry", + unique_together=set([("country", "trade_mark")]), ), ] diff --git a/src/ralph/trade_marks/migrations/0005_auto_20190312_0931.py b/src/ralph/trade_marks/migrations/0005_auto_20190312_0931.py index 02a29b2615..46b18419b2 100644 --- a/src/ralph/trade_marks/migrations/0005_auto_20190312_0931.py +++ b/src/ralph/trade_marks/migrations/0005_auto_20190312_0931.py @@ -5,15 +5,256 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0004_auto_20190221_0923'), + ("trade_marks", "0004_auto_20190221_0923"), ] operations = [ migrations.AlterField( - model_name='trademarkcountry', - name='country', - field=models.PositiveIntegerField(verbose_name='trade mark country', null=True, default=153, choices=[(1, 'Afghanistan'), (2, 'Albania'), (3, 'Algeria'), (4, 'American Samoa'), (5, 'Andorra'), (6, 'Angola'), (7, 'Anguilla'), (8, 'Antarctica'), (9, 'Antigua and Barbuda'), (10, 'Argentina'), (11, 'Armenia'), (12, 'Aruba'), (13, 'Australia'), (14, 'Austria'), (15, 'Azerbaijan'), (16, 'Bahamas'), (17, 'Bahrain'), (18, 'Bangladesh'), (19, 'Barbados'), (20, 'Belarus'), (21, 'Belgium'), (22, 'Belize'), (23, 'Benin'), (24, 'Bermuda'), (25, 'Bhutan'), (26, 'Bolivia'), (27, 'Bosnia and Herzegovina'), (28, 'Botswana'), (29, 'Brazil'), (30, 'Brunei'), (31, 'Bulgaria'), (32, 'Burkina Faso'), (33, 'Burundi'), (34, 'Cambodia'), (35, 'Cameroon'), (36, 'Canada'), (37, 'Cape Verde'), (38, 'Cayman Islands'), (39, 'Central African Republic'), (40, 'Chad'), (41, 'Chile'), (42, 'China'), (43, 'Colombia'), (44, 'Comoros'), (45, 'Congo Brazzaville'), (46, 'Congo Kinshasa'), (47, 'Cook Islands'), (48, 'Costa Rica'), (49, 'Cote Divoire'), (50, 'Croatia'), (51, 'Cuba'), (52, 'Cyprus'), (53, 'Czech Republic'), (54, 'Denmark'), (55, 'Djibouti'), (56, 'Dominica'), (57, 'Dominican Republic'), (58, 'Ecuador'), (59, 'Egypt'), (60, 'El Salvador'), (61, 'Equatorial Guinea'), (62, 'Eritrea'), (63, 'Estonia'), (64, 'Ethiopia'), (65, 'Faroe Islands'), (66, 'Fiji'), (67, 'Finland'), (68, 'France'), (69, 'French Polynesia'), (70, 'Gabon'), (71, 'Gambia'), (72, 'Georgia'), (73, 'Germany'), (74, 'Ghana'), (75, 'Gibraltar'), (76, 'Greece'), (77, 'Grenada'), (78, 'Guam'), (79, 'Guatemala'), (80, 'Guinea Bissau'), (81, 'Guinea'), (82, 'Guyana'), (83, 'Haiti'), (84, 'Honduras'), (85, 'Hong Kong'), (86, 'Hungary'), (87, 'Iceland'), (88, 'India'), (89, 'Indonesia'), (90, 'Iran'), (91, 'Iraq'), (92, 'Ireland'), (93, 'Israel'), (94, 'Italy'), (95, 'Jamaica'), (96, 'Japan'), (97, 'Jersey'), (98, 'Jordan'), (99, 'Kazakhstan'), (100, 'Kenya'), (101, 'Kiribati'), (102, 'Kuwait'), (103, 'Kyrgyzstan'), (104, 'Laos'), (105, 'Latvia'), (106, 'Lebanon'), (107, 'Lesotho'), (108, 'Liberia'), (109, 'Libya'), (110, 'Liechtenstein'), (111, 'Lithuania'), (112, 'Luxembourg'), (113, 'Macau'), (114, 'Macedonia'), (115, 'Madagascar'), (116, 'Malawi'), (117, 'Malaysia'), (118, 'Maldives'), (119, 'Mali'), (120, 'Malta'), (121, 'Marshall Islands'), (122, 'Mauritania'), (123, 'Mauritius'), (124, 'Mexico'), (125, 'Micronesia'), (126, 'Moldova'), (127, 'Monaco'), (128, 'Mongolia'), (129, 'Montenegro'), (130, 'Montserrat'), (131, 'Morocco'), (132, 'Mozambique'), (133, 'Myanmar'), (134, 'Namibia'), (135, 'Nauru'), (136, 'Nepal'), (137, 'Netherlands Antilles'), (138, 'Netherlands'), (139, 'New Zealand'), (140, 'Nicaragua'), (141, 'Niger'), (142, 'Nigeria'), (143, 'North Korea'), (144, 'Norway'), (145, 'Oman'), (146, 'Pakistan'), (147, 'Palau'), (148, 'Panama'), (149, 'Papua New Guinea'), (150, 'Paraguay'), (151, 'Peru'), (152, 'Philippines'), (153, 'Poland'), (154, 'Portugal'), (155, 'Puerto Rico'), (156, 'Qatar'), (157, 'Romania'), (158, 'Russian Federation'), (159, 'Rwanda'), (160, 'Saint Lucia'), (161, 'Samoa'), (162, 'San Marino'), (163, 'Sao Tome and Principe'), (164, 'Saudi Arabia'), (165, 'Senegal'), (166, 'Serbia'), (167, 'Seychelles'), (168, 'Sierra Leone'), (169, 'Singapore'), (170, 'Slovakia'), (171, 'Slovenia'), (172, 'Solomon Islands'), (173, 'Somalia'), (174, 'South Africa'), (175, 'South Korea'), (176, 'Spain'), (177, 'Sri Lanka'), (178, 'St Kitts and Nevis'), (179, 'St Vincent and the Grenadines'), (180, 'Sudan'), (181, 'Suriname'), (182, 'Swaziland'), (183, 'Sweden'), (184, 'Switzerland'), (185, 'Syria'), (186, 'Tajikistan'), (187, 'Taiwan'), (188, 'Tanzania'), (189, 'Thailand'), (190, 'Timor Leste'), (191, 'Togo'), (192, 'Tonga'), (193, 'Trinidad and Tobago'), (194, 'Tunisia'), (195, 'Turkey'), (196, 'Turkmenistan'), (197, 'Turks and Caicos Islands'), (198, 'Tuvalu'), (199, 'Uganda'), (200, 'Ukraine'), (201, 'United Arab Emirates'), (202, 'United Kingdom'), (203, 'United States of America'), (204, 'Uruguay'), (205, 'Uzbekistan'), (206, 'Vanuatu'), (207, 'Vatican City'), (208, 'Venezuela'), (209, 'Viet Nam'), (210, 'Virgin Islands British'), (211, 'Virgin Islands US'), (212, 'Western Sahara'), (213, 'Yemen'), (214, 'Zambia'), (215, 'Zimbabwe'), (301, 'England'), (302, 'Northern Ireland'), (303, 'Wales'), (304, 'Scotland'), (601, 'Northern Cyprus'), (602, 'Palestine'), (603, 'Somaliland'), (901, 'African Union'), (902, 'Arab League'), (903, 'Association of Southeast Asian Nations'), (904, 'Caricom'), (905, 'Commonwealth of Independent States'), (906, 'Commonwealth of Nations'), (907, 'European Union'), (908, 'Islamic Conference'), (909, 'NATO'), (910, 'Olimpic Movement'), (911, 'OPEC'), (912, 'Red Cross'), (913, 'United Nations')], blank=True), + model_name="trademarkcountry", + name="country", + field=models.PositiveIntegerField( + verbose_name="trade mark country", + null=True, + default=153, + choices=[ + (1, "Afghanistan"), + (2, "Albania"), + (3, "Algeria"), + (4, "American Samoa"), + (5, "Andorra"), + (6, "Angola"), + (7, "Anguilla"), + (8, "Antarctica"), + (9, "Antigua and Barbuda"), + (10, "Argentina"), + (11, "Armenia"), + (12, "Aruba"), + (13, "Australia"), + (14, "Austria"), + (15, "Azerbaijan"), + (16, "Bahamas"), + (17, "Bahrain"), + (18, "Bangladesh"), + (19, "Barbados"), + (20, "Belarus"), + (21, "Belgium"), + (22, "Belize"), + (23, "Benin"), + (24, "Bermuda"), + (25, "Bhutan"), + (26, "Bolivia"), + (27, "Bosnia and Herzegovina"), + (28, "Botswana"), + (29, "Brazil"), + (30, "Brunei"), + (31, "Bulgaria"), + (32, "Burkina Faso"), + (33, "Burundi"), + (34, "Cambodia"), + (35, "Cameroon"), + (36, "Canada"), + (37, "Cape Verde"), + (38, "Cayman Islands"), + (39, "Central African Republic"), + (40, "Chad"), + (41, "Chile"), + (42, "China"), + (43, "Colombia"), + (44, "Comoros"), + (45, "Congo Brazzaville"), + (46, "Congo Kinshasa"), + (47, "Cook Islands"), + (48, "Costa Rica"), + (49, "Cote Divoire"), + (50, "Croatia"), + (51, "Cuba"), + (52, "Cyprus"), + (53, "Czech Republic"), + (54, "Denmark"), + (55, "Djibouti"), + (56, "Dominica"), + (57, "Dominican Republic"), + (58, "Ecuador"), + (59, "Egypt"), + (60, "El Salvador"), + (61, "Equatorial Guinea"), + (62, "Eritrea"), + (63, "Estonia"), + (64, "Ethiopia"), + (65, "Faroe Islands"), + (66, "Fiji"), + (67, "Finland"), + (68, "France"), + (69, "French Polynesia"), + (70, "Gabon"), + (71, "Gambia"), + (72, "Georgia"), + (73, "Germany"), + (74, "Ghana"), + (75, "Gibraltar"), + (76, "Greece"), + (77, "Grenada"), + (78, "Guam"), + (79, "Guatemala"), + (80, "Guinea Bissau"), + (81, "Guinea"), + (82, "Guyana"), + (83, "Haiti"), + (84, "Honduras"), + (85, "Hong Kong"), + (86, "Hungary"), + (87, "Iceland"), + (88, "India"), + (89, "Indonesia"), + (90, "Iran"), + (91, "Iraq"), + (92, "Ireland"), + (93, "Israel"), + (94, "Italy"), + (95, "Jamaica"), + (96, "Japan"), + (97, "Jersey"), + (98, "Jordan"), + (99, "Kazakhstan"), + (100, "Kenya"), + (101, "Kiribati"), + (102, "Kuwait"), + (103, "Kyrgyzstan"), + (104, "Laos"), + (105, "Latvia"), + (106, "Lebanon"), + (107, "Lesotho"), + (108, "Liberia"), + (109, "Libya"), + (110, "Liechtenstein"), + (111, "Lithuania"), + (112, "Luxembourg"), + (113, "Macau"), + (114, "Macedonia"), + (115, "Madagascar"), + (116, "Malawi"), + (117, "Malaysia"), + (118, "Maldives"), + (119, "Mali"), + (120, "Malta"), + (121, "Marshall Islands"), + (122, "Mauritania"), + (123, "Mauritius"), + (124, "Mexico"), + (125, "Micronesia"), + (126, "Moldova"), + (127, "Monaco"), + (128, "Mongolia"), + (129, "Montenegro"), + (130, "Montserrat"), + (131, "Morocco"), + (132, "Mozambique"), + (133, "Myanmar"), + (134, "Namibia"), + (135, "Nauru"), + (136, "Nepal"), + (137, "Netherlands Antilles"), + (138, "Netherlands"), + (139, "New Zealand"), + (140, "Nicaragua"), + (141, "Niger"), + (142, "Nigeria"), + (143, "North Korea"), + (144, "Norway"), + (145, "Oman"), + (146, "Pakistan"), + (147, "Palau"), + (148, "Panama"), + (149, "Papua New Guinea"), + (150, "Paraguay"), + (151, "Peru"), + (152, "Philippines"), + (153, "Poland"), + (154, "Portugal"), + (155, "Puerto Rico"), + (156, "Qatar"), + (157, "Romania"), + (158, "Russian Federation"), + (159, "Rwanda"), + (160, "Saint Lucia"), + (161, "Samoa"), + (162, "San Marino"), + (163, "Sao Tome and Principe"), + (164, "Saudi Arabia"), + (165, "Senegal"), + (166, "Serbia"), + (167, "Seychelles"), + (168, "Sierra Leone"), + (169, "Singapore"), + (170, "Slovakia"), + (171, "Slovenia"), + (172, "Solomon Islands"), + (173, "Somalia"), + (174, "South Africa"), + (175, "South Korea"), + (176, "Spain"), + (177, "Sri Lanka"), + (178, "St Kitts and Nevis"), + (179, "St Vincent and the Grenadines"), + (180, "Sudan"), + (181, "Suriname"), + (182, "Swaziland"), + (183, "Sweden"), + (184, "Switzerland"), + (185, "Syria"), + (186, "Tajikistan"), + (187, "Taiwan"), + (188, "Tanzania"), + (189, "Thailand"), + (190, "Timor Leste"), + (191, "Togo"), + (192, "Tonga"), + (193, "Trinidad and Tobago"), + (194, "Tunisia"), + (195, "Turkey"), + (196, "Turkmenistan"), + (197, "Turks and Caicos Islands"), + (198, "Tuvalu"), + (199, "Uganda"), + (200, "Ukraine"), + (201, "United Arab Emirates"), + (202, "United Kingdom"), + (203, "United States of America"), + (204, "Uruguay"), + (205, "Uzbekistan"), + (206, "Vanuatu"), + (207, "Vatican City"), + (208, "Venezuela"), + (209, "Viet Nam"), + (210, "Virgin Islands British"), + (211, "Virgin Islands US"), + (212, "Western Sahara"), + (213, "Yemen"), + (214, "Zambia"), + (215, "Zimbabwe"), + (301, "England"), + (302, "Northern Ireland"), + (303, "Wales"), + (304, "Scotland"), + (601, "Northern Cyprus"), + (602, "Palestine"), + (603, "Somaliland"), + (901, "African Union"), + (902, "Arab League"), + (903, "Association of Southeast Asian Nations"), + (904, "Caricom"), + (905, "Commonwealth of Independent States"), + (906, "Commonwealth of Nations"), + (907, "European Union"), + (908, "Islamic Conference"), + (909, "NATO"), + (910, "Olimpic Movement"), + (911, "OPEC"), + (912, "Red Cross"), + (913, "United Nations"), + ], + blank=True, + ), ), ] diff --git a/src/ralph/trade_marks/migrations/0006_trademark_valid_from.py b/src/ralph/trade_marks/migrations/0006_trademark_valid_from.py index 853ec1ff1c..41dd6906a3 100644 --- a/src/ralph/trade_marks/migrations/0006_trademark_valid_from.py +++ b/src/ralph/trade_marks/migrations/0006_trademark_valid_from.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0005_auto_20190312_0931'), + ("trade_marks", "0005_auto_20190312_0931"), ] operations = [ migrations.AddField( - model_name='trademark', - name='valid_from', + model_name="trademark", + name="valid_from", field=models.DateField(blank=True, null=True), ), ] diff --git a/src/ralph/trade_marks/migrations/0007_auto_20190813_0914.py b/src/ralph/trade_marks/migrations/0007_auto_20190813_0914.py index aee169f01a..aa65b9dfa7 100644 --- a/src/ralph/trade_marks/migrations/0007_auto_20190813_0914.py +++ b/src/ralph/trade_marks/migrations/0007_auto_20190813_0914.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0006_trademark_valid_from'), + ("trade_marks", "0006_trademark_valid_from"), ] operations = [ migrations.AlterField( - model_name='trademark', - name='valid_to', + model_name="trademark", + name="valid_to", field=models.DateField(blank=True, null=True), ), ] diff --git a/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py b/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py index e97a434966..94c719c376 100644 --- a/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py +++ b/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py @@ -9,164 +9,409 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('domains', '0007_auto_20200909_1012'), - ('assets', '0032_auto_20200909_1012'), - ('trade_marks', '0007_auto_20190813_0914'), + ("domains", "0007_auto_20200909_1012"), + ("assets", "0032_auto_20200909_1012"), + ("trade_marks", "0007_auto_20190813_0914"), ] operations = [ migrations.CreateModel( - name='Design', + name="Design", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, serialize=False, auto_created=True, parent_link=True, to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(max_length=255)), - ('registrant_number', models.CharField(verbose_name='Registrant number', max_length=255)), - ('type', models.PositiveIntegerField(verbose_name='Trade Mark type', default=2, choices=[(1, 'Word'), (2, 'Figurative'), (3, 'Word - Figurative')])), - ('image', models.ImageField(blank=True, null=True, upload_to=ralph.trade_marks.models.upload_dir)), - ('registrant_class', models.CharField(verbose_name='Registrant class', max_length=255)), - ('valid_from', models.DateField(blank=True, null=True)), - ('valid_to', models.DateField(blank=True, null=True)), - ('order_number_url', models.URLField(max_length=255, blank=True, null=True)), - ('status', models.PositiveIntegerField(verbose_name='Trade Mark status', default=5, choices=[(1, 'Application filed'), (2, 'Application refused'), (3, 'Application withdrawn'), (4, 'Application opposed'), (5, 'Registered'), (6, 'Registration invalidated'), (7, 'Registration expired')])), - ('additional_markings', models.ManyToManyField(blank=True, to='trade_marks.ProviderAdditionalMarking')), - ('business_owner', models.ForeignKey(related_name='design_business_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + serialize=False, + auto_created=True, + parent_link=True, + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("name", models.CharField(max_length=255)), + ( + "registrant_number", + models.CharField(verbose_name="Registrant number", max_length=255), + ), + ( + "type", + models.PositiveIntegerField( + verbose_name="Trade Mark type", + default=2, + choices=[ + (1, "Word"), + (2, "Figurative"), + (3, "Word - Figurative"), + ], + ), + ), + ( + "image", + models.ImageField( + blank=True, + null=True, + upload_to=ralph.trade_marks.models.upload_dir, + ), + ), + ( + "registrant_class", + models.CharField(verbose_name="Registrant class", max_length=255), + ), + ("valid_from", models.DateField(blank=True, null=True)), + ("valid_to", models.DateField(blank=True, null=True)), + ( + "order_number_url", + models.URLField(max_length=255, blank=True, null=True), + ), + ( + "status", + models.PositiveIntegerField( + verbose_name="Trade Mark status", + default=5, + choices=[ + (1, "Application filed"), + (2, "Application refused"), + (3, "Application withdrawn"), + (4, "Application opposed"), + (5, "Registered"), + (6, "Registration invalidated"), + (7, "Registration expired"), + ], + ), + ), + ( + "additional_markings", + models.ManyToManyField( + blank=True, to="trade_marks.ProviderAdditionalMarking" + ), + ), + ( + "business_owner", + models.ForeignKey( + related_name="design_business_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject'), + bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, "assets.baseobject"), ), migrations.CreateModel( - name='DesignAdditionalCountry', + name="DesignAdditionalCountry", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('country', models.ForeignKey(to='trade_marks.TradeMarkCountry', on_delete=django.db.models.deletion.CASCADE)), - ('design', models.ForeignKey(to='trade_marks.Design', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "country", + models.ForeignKey( + to="trade_marks.TradeMarkCountry", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "design", + models.ForeignKey( + to="trade_marks.Design", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Design Additional Country', - 'verbose_name_plural': 'Design Additional Countries', + "verbose_name": "Design Additional Country", + "verbose_name_plural": "Design Additional Countries", }, ), migrations.CreateModel( - name='DesignsLinkedDomains', + name="DesignsLinkedDomains", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('design', models.ForeignKey(to='trade_marks.Design', on_delete=django.db.models.deletion.CASCADE)), - ('domain', models.ForeignKey(related_name='design', to='domains.Domain', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "design", + models.ForeignKey( + to="trade_marks.Design", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "domain", + models.ForeignKey( + related_name="design", + to="domains.Domain", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Design Linked Domain', - 'verbose_name_plural': 'Design Linked Domains', + "verbose_name": "Design Linked Domain", + "verbose_name_plural": "Design Linked Domains", }, ), migrations.CreateModel( - name='Patent', + name="Patent", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, serialize=False, auto_created=True, parent_link=True, to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(max_length=255)), - ('registrant_number', models.CharField(verbose_name='Registrant number', max_length=255)), - ('type', models.PositiveIntegerField(verbose_name='Trade Mark type', default=2, choices=[(1, 'Word'), (2, 'Figurative'), (3, 'Word - Figurative')])), - ('image', models.ImageField(blank=True, null=True, upload_to=ralph.trade_marks.models.upload_dir)), - ('registrant_class', models.CharField(verbose_name='Registrant class', max_length=255)), - ('valid_from', models.DateField(blank=True, null=True)), - ('valid_to', models.DateField(blank=True, null=True)), - ('order_number_url', models.URLField(max_length=255, blank=True, null=True)), - ('status', models.PositiveIntegerField(verbose_name='Trade Mark status', default=5, choices=[(1, 'Application filed'), (2, 'Application refused'), (3, 'Application withdrawn'), (4, 'Application opposed'), (5, 'Registered'), (6, 'Registration invalidated'), (7, 'Registration expired')])), - ('additional_markings', models.ManyToManyField(blank=True, to='trade_marks.ProviderAdditionalMarking')), - ('business_owner', models.ForeignKey(related_name='patent_business_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + serialize=False, + auto_created=True, + parent_link=True, + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("name", models.CharField(max_length=255)), + ( + "registrant_number", + models.CharField(verbose_name="Registrant number", max_length=255), + ), + ( + "type", + models.PositiveIntegerField( + verbose_name="Trade Mark type", + default=2, + choices=[ + (1, "Word"), + (2, "Figurative"), + (3, "Word - Figurative"), + ], + ), + ), + ( + "image", + models.ImageField( + blank=True, + null=True, + upload_to=ralph.trade_marks.models.upload_dir, + ), + ), + ( + "registrant_class", + models.CharField(verbose_name="Registrant class", max_length=255), + ), + ("valid_from", models.DateField(blank=True, null=True)), + ("valid_to", models.DateField(blank=True, null=True)), + ( + "order_number_url", + models.URLField(max_length=255, blank=True, null=True), + ), + ( + "status", + models.PositiveIntegerField( + verbose_name="Trade Mark status", + default=5, + choices=[ + (1, "Application filed"), + (2, "Application refused"), + (3, "Application withdrawn"), + (4, "Application opposed"), + (5, "Registered"), + (6, "Registration invalidated"), + (7, "Registration expired"), + ], + ), + ), + ( + "additional_markings", + models.ManyToManyField( + blank=True, to="trade_marks.ProviderAdditionalMarking" + ), + ), + ( + "business_owner", + models.ForeignKey( + related_name="patent_business_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject'), + bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, "assets.baseobject"), ), migrations.CreateModel( - name='PatentAdditionalCountry', + name="PatentAdditionalCountry", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('country', models.ForeignKey(to='trade_marks.TradeMarkCountry', on_delete=django.db.models.deletion.CASCADE)), - ('patent', models.ForeignKey(to='trade_marks.Patent', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "country", + models.ForeignKey( + to="trade_marks.TradeMarkCountry", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "patent", + models.ForeignKey( + to="trade_marks.Patent", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Patent Additional Country', - 'verbose_name_plural': 'Patent Additional Countries', + "verbose_name": "Patent Additional Country", + "verbose_name_plural": "Patent Additional Countries", }, ), migrations.CreateModel( - name='PatentsLinkedDomains', + name="PatentsLinkedDomains", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('domain', models.ForeignKey(related_name='patent', to='domains.Domain', on_delete=django.db.models.deletion.CASCADE)), - ('patent', models.ForeignKey(to='trade_marks.Patent', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "domain", + models.ForeignKey( + related_name="patent", + to="domains.Domain", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "patent", + models.ForeignKey( + to="trade_marks.Patent", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Patent Linked Domain', - 'verbose_name_plural': 'Patent Linked Domains', + "verbose_name": "Patent Linked Domain", + "verbose_name_plural": "Patent Linked Domains", }, ), migrations.AlterField( - model_name='trademark', - name='name', + model_name="trademark", + name="name", field=models.CharField(max_length=255), ), migrations.AddField( - model_name='patent', - name='domains', - field=models.ManyToManyField(related_name='_patent_domains_+', to='domains.Domain', through='trade_marks.PatentsLinkedDomains'), + model_name="patent", + name="domains", + field=models.ManyToManyField( + related_name="_patent_domains_+", + to="domains.Domain", + through="trade_marks.PatentsLinkedDomains", + ), ), migrations.AddField( - model_name='patent', - name='holder', - field=models.ForeignKey(verbose_name='Trade Mark holder', blank=True, null=True, to='assets.AssetHolder', on_delete=django.db.models.deletion.CASCADE), + model_name="patent", + name="holder", + field=models.ForeignKey( + verbose_name="Trade Mark holder", + blank=True, + null=True, + to="assets.AssetHolder", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='patent', - name='registrar_institution', - field=models.ForeignKey(null=True, to='trade_marks.TradeMarkRegistrarInstitution', on_delete=django.db.models.deletion.CASCADE), + model_name="patent", + name="registrar_institution", + field=models.ForeignKey( + null=True, + to="trade_marks.TradeMarkRegistrarInstitution", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='patent', - name='technical_owner', - field=models.ForeignKey(related_name='patent_technical_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE), + model_name="patent", + name="technical_owner", + field=models.ForeignKey( + related_name="patent_technical_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='design', - name='domains', - field=models.ManyToManyField(related_name='_design_domains_+', to='domains.Domain', through='trade_marks.DesignsLinkedDomains'), + model_name="design", + name="domains", + field=models.ManyToManyField( + related_name="_design_domains_+", + to="domains.Domain", + through="trade_marks.DesignsLinkedDomains", + ), ), migrations.AddField( - model_name='design', - name='holder', - field=models.ForeignKey(verbose_name='Trade Mark holder', blank=True, null=True, to='assets.AssetHolder', on_delete=django.db.models.deletion.CASCADE), + model_name="design", + name="holder", + field=models.ForeignKey( + verbose_name="Trade Mark holder", + blank=True, + null=True, + to="assets.AssetHolder", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='design', - name='registrar_institution', - field=models.ForeignKey(null=True, to='trade_marks.TradeMarkRegistrarInstitution', on_delete=django.db.models.deletion.CASCADE), + model_name="design", + name="registrar_institution", + field=models.ForeignKey( + null=True, + to="trade_marks.TradeMarkRegistrarInstitution", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='design', - name='technical_owner', - field=models.ForeignKey(related_name='design_technical_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE), + model_name="design", + name="technical_owner", + field=models.ForeignKey( + related_name="design_technical_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterUniqueTogether( - name='patentslinkeddomains', - unique_together=set([('patent', 'domain')]), + name="patentslinkeddomains", + unique_together=set([("patent", "domain")]), ), migrations.AlterUniqueTogether( - name='patentadditionalcountry', - unique_together=set([('country', 'patent')]), + name="patentadditionalcountry", + unique_together=set([("country", "patent")]), ), migrations.AlterUniqueTogether( - name='designslinkeddomains', - unique_together=set([('design', 'domain')]), + name="designslinkeddomains", + unique_together=set([("design", "domain")]), ), migrations.AlterUniqueTogether( - name='designadditionalcountry', - unique_together=set([('country', 'design')]), + name="designadditionalcountry", + unique_together=set([("country", "design")]), ), ] diff --git a/src/ralph/trade_marks/migrations/0009_auto_20210630_1719.py b/src/ralph/trade_marks/migrations/0009_auto_20210630_1719.py index 8184a20cd4..9f8e6a12da 100644 --- a/src/ralph/trade_marks/migrations/0009_auto_20210630_1719.py +++ b/src/ralph/trade_marks/migrations/0009_auto_20210630_1719.py @@ -6,85 +6,141 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0008_auto_20210625_0738'), + ("trade_marks", "0008_auto_20210625_0738"), ] operations = [ migrations.RenameField( - model_name='design', - old_name='registrant_class', - new_name='classes', + model_name="design", + old_name="registrant_class", + new_name="classes", ), migrations.RenameField( - model_name='design', - old_name='registrant_number', - new_name='number', + model_name="design", + old_name="registrant_number", + new_name="number", ), migrations.RenameField( - model_name='patent', - old_name='registrant_class', - new_name='classes', + model_name="patent", + old_name="registrant_class", + new_name="classes", ), migrations.RenameField( - model_name='patent', - old_name='registrant_number', - new_name='number', + model_name="patent", + old_name="registrant_number", + new_name="number", ), migrations.RenameField( - model_name='trademark', - old_name='registrant_class', - new_name='classes', + model_name="trademark", + old_name="registrant_class", + new_name="classes", ), migrations.RenameField( - model_name='trademark', - old_name='registrant_number', - new_name='number', + model_name="trademark", + old_name="registrant_number", + new_name="number", ), migrations.AlterField( - model_name='design', - name='holder', - field=models.ForeignKey(blank=True, null=True, to='assets.AssetHolder', on_delete=django.db.models.deletion.CASCADE), + model_name="design", + name="holder", + field=models.ForeignKey( + blank=True, + null=True, + to="assets.AssetHolder", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterField( - model_name='design', - name='status', - field=models.PositiveIntegerField(default=5, choices=[(1, 'Application filed'), (2, 'Application refused'), (3, 'Application withdrawn'), (4, 'Application opposed'), (5, 'Registered'), (6, 'Registration invalidated'), (7, 'Registration expired')]), + model_name="design", + name="status", + field=models.PositiveIntegerField( + default=5, + choices=[ + (1, "Application filed"), + (2, "Application refused"), + (3, "Application withdrawn"), + (4, "Application opposed"), + (5, "Registered"), + (6, "Registration invalidated"), + (7, "Registration expired"), + ], + ), ), migrations.AlterField( - model_name='design', - name='type', - field=models.PositiveIntegerField(default=2, choices=[(1, 'Word'), (2, 'Figurative'), (3, 'Word - Figurative')]), + model_name="design", + name="type", + field=models.PositiveIntegerField( + default=2, + choices=[(1, "Word"), (2, "Figurative"), (3, "Word - Figurative")], + ), ), migrations.AlterField( - model_name='patent', - name='holder', - field=models.ForeignKey(blank=True, null=True, to='assets.AssetHolder', on_delete=django.db.models.deletion.CASCADE), + model_name="patent", + name="holder", + field=models.ForeignKey( + blank=True, + null=True, + to="assets.AssetHolder", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterField( - model_name='patent', - name='status', - field=models.PositiveIntegerField(default=5, choices=[(1, 'Application filed'), (2, 'Application refused'), (3, 'Application withdrawn'), (4, 'Application opposed'), (5, 'Registered'), (6, 'Registration invalidated'), (7, 'Registration expired')]), + model_name="patent", + name="status", + field=models.PositiveIntegerField( + default=5, + choices=[ + (1, "Application filed"), + (2, "Application refused"), + (3, "Application withdrawn"), + (4, "Application opposed"), + (5, "Registered"), + (6, "Registration invalidated"), + (7, "Registration expired"), + ], + ), ), migrations.AlterField( - model_name='patent', - name='type', - field=models.PositiveIntegerField(default=2, choices=[(1, 'Word'), (2, 'Figurative'), (3, 'Word - Figurative')]), + model_name="patent", + name="type", + field=models.PositiveIntegerField( + default=2, + choices=[(1, "Word"), (2, "Figurative"), (3, "Word - Figurative")], + ), ), migrations.AlterField( - model_name='trademark', - name='holder', - field=models.ForeignKey(blank=True, null=True, to='assets.AssetHolder', on_delete=django.db.models.deletion.CASCADE), + model_name="trademark", + name="holder", + field=models.ForeignKey( + blank=True, + null=True, + to="assets.AssetHolder", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AlterField( - model_name='trademark', - name='status', - field=models.PositiveIntegerField(default=5, choices=[(1, 'Application filed'), (2, 'Application refused'), (3, 'Application withdrawn'), (4, 'Application opposed'), (5, 'Registered'), (6, 'Registration invalidated'), (7, 'Registration expired')]), + model_name="trademark", + name="status", + field=models.PositiveIntegerField( + default=5, + choices=[ + (1, "Application filed"), + (2, "Application refused"), + (3, "Application withdrawn"), + (4, "Application opposed"), + (5, "Registered"), + (6, "Registration invalidated"), + (7, "Registration expired"), + ], + ), ), migrations.AlterField( - model_name='trademark', - name='type', - field=models.PositiveIntegerField(default=2, choices=[(1, 'Word'), (2, 'Figurative'), (3, 'Word - Figurative')]), + model_name="trademark", + name="type", + field=models.PositiveIntegerField( + default=2, + choices=[(1, "Word"), (2, "Figurative"), (3, "Word - Figurative")], + ), ), ] diff --git a/src/ralph/trade_marks/migrations/0010_auto_20210702_1129.py b/src/ralph/trade_marks/migrations/0010_auto_20210702_1129.py index 4c1bc3bc54..93abb7ed24 100644 --- a/src/ralph/trade_marks/migrations/0010_auto_20210702_1129.py +++ b/src/ralph/trade_marks/migrations/0010_auto_20210702_1129.py @@ -5,68 +5,71 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0009_auto_20210630_1719'), + ("trade_marks", "0009_auto_20210630_1719"), ] operations = [ migrations.RemoveField( - model_name='design', - name='type', + model_name="design", + name="type", ), migrations.RemoveField( - model_name='patent', - name='type', + model_name="patent", + name="type", ), migrations.AddField( - model_name='design', - name='database_link', + model_name="design", + name="database_link", field=models.URLField(max_length=255, blank=True, null=True), ), migrations.AddField( - model_name='patent', - name='database_link', + model_name="patent", + name="database_link", field=models.URLField(max_length=255, blank=True, null=True), ), migrations.AddField( - model_name='trademark', - name='database_link', + model_name="trademark", + name="database_link", field=models.URLField(max_length=255, blank=True, null=True), ), migrations.AlterField( - model_name='design', - name='classes', + model_name="design", + name="classes", field=models.CharField(max_length=255), ), migrations.AlterField( - model_name='design', - name='number', + model_name="design", + name="number", field=models.CharField(max_length=255), ), migrations.AlterField( - model_name='patent', - name='classes', + model_name="patent", + name="classes", field=models.CharField(max_length=255), ), migrations.AlterField( - model_name='patent', - name='number', + model_name="patent", + name="number", field=models.CharField(max_length=255), ), migrations.AlterField( - model_name='trademark', - name='classes', + model_name="trademark", + name="classes", field=models.CharField(max_length=255), ), migrations.AlterField( - model_name='trademark', - name='number', + model_name="trademark", + name="number", field=models.CharField(max_length=255), ), migrations.AlterField( - model_name='trademark', - name='type', - field=models.PositiveIntegerField(verbose_name='Trade Mark type', default=2, choices=[(1, 'Word'), (2, 'Figurative'), (3, 'Word - Figurative')]), + model_name="trademark", + name="type", + field=models.PositiveIntegerField( + verbose_name="Trade Mark type", + default=2, + choices=[(1, "Word"), (2, "Figurative"), (3, "Word - Figurative")], + ), ), ] diff --git a/src/ralph/trade_marks/migrations/0011_trademarkkind.py b/src/ralph/trade_marks/migrations/0011_trademarkkind.py index ea9d45b8a1..7146e45718 100644 --- a/src/ralph/trade_marks/migrations/0011_trademarkkind.py +++ b/src/ralph/trade_marks/migrations/0011_trademarkkind.py @@ -6,17 +6,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0010_auto_20210702_1129'), + ("trade_marks", "0010_auto_20210702_1129"), ] operations = [ migrations.CreateModel( - name='TradeMarkKind', + name="TradeMarkKind", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('type', models.CharField(max_length=255)), + ("id", models.AutoField(primary_key=True, serialize=False)), + ("type", models.CharField(max_length=255)), ], bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), diff --git a/src/ralph/trade_marks/migrations/0012_populate_trademark_kinds.py b/src/ralph/trade_marks/migrations/0012_populate_trademark_kinds.py index 7c967a757c..66a2095efb 100644 --- a/src/ralph/trade_marks/migrations/0012_populate_trademark_kinds.py +++ b/src/ralph/trade_marks/migrations/0012_populate_trademark_kinds.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations def populate_trademark_kinds(apps, schema_editor): @@ -9,29 +9,28 @@ def populate_trademark_kinds(apps, schema_editor): TradeMarkKind( id=1, - type='Word', + type="Word", ).save() TradeMarkKind( id=2, - type='Figurative', + type="Figurative", ).save() TradeMarkKind( id=3, - type='Word - Figurative', + type="Word - Figurative", ).save() TradeMarkKind( id=4, - type='3D', + type="3D", ).save() class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0011_trademarkkind'), + ("trade_marks", "0011_trademarkkind"), ] operations = [ diff --git a/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py b/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py index 4830d085af..a2d1418a6a 100644 --- a/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py +++ b/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py @@ -6,15 +6,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0012_populate_trademark_kinds'), + ("trade_marks", "0012_populate_trademark_kinds"), ] operations = [ migrations.AlterField( - model_name='trademark', - name='type', - field=models.ForeignKey(verbose_name='Trade Mark type', related_name='trademarks', on_delete=django.db.models.deletion.DO_NOTHING, to='trade_marks.TradeMarkKind'), + model_name="trademark", + name="type", + field=models.ForeignKey( + verbose_name="Trade Mark type", + related_name="trademarks", + on_delete=django.db.models.deletion.DO_NOTHING, + to="trade_marks.TradeMarkKind", + ), ), ] diff --git a/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py b/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py index dc618cf5fd..910495cc5a 100644 --- a/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py +++ b/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py @@ -6,15 +6,20 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0013_auto_20211206_1400'), + ("trade_marks", "0013_auto_20211206_1400"), ] operations = [ migrations.AlterField( - model_name='trademark', - name='type', - field=models.ForeignKey(verbose_name='Trade Mark type', default=2, related_name='trademarks', on_delete=django.db.models.deletion.DO_NOTHING, to='trade_marks.TradeMarkKind'), + model_name="trademark", + name="type", + field=models.ForeignKey( + verbose_name="Trade Mark type", + default=2, + related_name="trademarks", + on_delete=django.db.models.deletion.DO_NOTHING, + to="trade_marks.TradeMarkKind", + ), ), ] diff --git a/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py b/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py index d568f3220b..53a7696d62 100644 --- a/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py +++ b/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py @@ -9,69 +9,184 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0033_auto_20211115_1125'), + ("assets", "0033_auto_20211115_1125"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('domains', '0007_auto_20200909_1012'), - ('trade_marks', '0014_auto_20211207_1118'), + ("domains", "0007_auto_20200909_1012"), + ("trade_marks", "0014_auto_20211207_1118"), ] operations = [ migrations.CreateModel( - name='UtilityModel', + name="UtilityModel", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, serialize=False, auto_created=True, parent_link=True, to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(max_length=255)), - ('number', models.CharField(max_length=255)), - ('image', models.ImageField(blank=True, null=True, upload_to=ralph.trade_marks.models.upload_dir)), - ('classes', models.CharField(max_length=255)), - ('valid_from', models.DateField(blank=True, null=True)), - ('valid_to', models.DateField(blank=True, null=True)), - ('order_number_url', models.URLField(max_length=255, blank=True, null=True)), - ('status', models.PositiveIntegerField(default=5, choices=[(1, 'Application filed'), (2, 'Application refused'), (3, 'Application withdrawn'), (4, 'Application opposed'), (5, 'Registered'), (6, 'Registration invalidated'), (7, 'Registration expired')])), - ('database_link', models.URLField(max_length=255, blank=True, null=True)), - ('additional_markings', models.ManyToManyField(blank=True, to='trade_marks.ProviderAdditionalMarking')), - ('business_owner', models.ForeignKey(related_name='utilitymodel_business_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE)), - ('holder', models.ForeignKey(blank=True, null=True, to='assets.AssetHolder', on_delete=django.db.models.deletion.CASCADE)), - ('registrar_institution', models.ForeignKey(null=True, to='trade_marks.TradeMarkRegistrarInstitution', on_delete=django.db.models.deletion.CASCADE)), - ('technical_owner', models.ForeignKey(related_name='utilitymodel_technical_owner', to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + serialize=False, + auto_created=True, + parent_link=True, + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("name", models.CharField(max_length=255)), + ("number", models.CharField(max_length=255)), + ( + "image", + models.ImageField( + blank=True, + null=True, + upload_to=ralph.trade_marks.models.upload_dir, + ), + ), + ("classes", models.CharField(max_length=255)), + ("valid_from", models.DateField(blank=True, null=True)), + ("valid_to", models.DateField(blank=True, null=True)), + ( + "order_number_url", + models.URLField(max_length=255, blank=True, null=True), + ), + ( + "status", + models.PositiveIntegerField( + default=5, + choices=[ + (1, "Application filed"), + (2, "Application refused"), + (3, "Application withdrawn"), + (4, "Application opposed"), + (5, "Registered"), + (6, "Registration invalidated"), + (7, "Registration expired"), + ], + ), + ), + ( + "database_link", + models.URLField(max_length=255, blank=True, null=True), + ), + ( + "additional_markings", + models.ManyToManyField( + blank=True, to="trade_marks.ProviderAdditionalMarking" + ), + ), + ( + "business_owner", + models.ForeignKey( + related_name="utilitymodel_business_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "holder", + models.ForeignKey( + blank=True, + null=True, + to="assets.AssetHolder", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "registrar_institution", + models.ForeignKey( + null=True, + to="trade_marks.TradeMarkRegistrarInstitution", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "technical_owner", + models.ForeignKey( + related_name="utilitymodel_technical_owner", + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, 'assets.baseobject', models.Model), + bases=( + ralph.lib.mixins.models.AdminAbsoluteUrlMixin, + "assets.baseobject", + models.Model, + ), ), migrations.CreateModel( - name='UtilityModelAdditionalCountry', + name="UtilityModelAdditionalCountry", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('country', models.ForeignKey(to='trade_marks.TradeMarkCountry', on_delete=django.db.models.deletion.CASCADE)), - ('utility_model', models.ForeignKey(to='trade_marks.UtilityModel', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "country", + models.ForeignKey( + to="trade_marks.TradeMarkCountry", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "utility_model", + models.ForeignKey( + to="trade_marks.UtilityModel", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Utility Model Additional Country', - 'verbose_name_plural': 'Utility Model Additional Countries', + "verbose_name": "Utility Model Additional Country", + "verbose_name_plural": "Utility Model Additional Countries", }, ), migrations.CreateModel( - name='UtilityModelLinkedDomains', + name="UtilityModelLinkedDomains", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('domain', models.ForeignKey(related_name='utility_model', to='domains.Domain', on_delete=django.db.models.deletion.CASCADE)), - ('utility_model', models.ForeignKey(to='trade_marks.UtilityModel', on_delete=django.db.models.deletion.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "domain", + models.ForeignKey( + related_name="utility_model", + to="domains.Domain", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "utility_model", + models.ForeignKey( + to="trade_marks.UtilityModel", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Utility Model Linked Domain', - 'verbose_name_plural': 'Utility Model Linked Domains', + "verbose_name": "Utility Model Linked Domain", + "verbose_name_plural": "Utility Model Linked Domains", }, ), migrations.AlterUniqueTogether( - name='utilitymodellinkeddomains', - unique_together=set([('utility_model', 'domain')]), + name="utilitymodellinkeddomains", + unique_together=set([("utility_model", "domain")]), ), migrations.AlterUniqueTogether( - name='utilitymodeladditionalcountry', - unique_together=set([('country', 'utility_model')]), + name="utilitymodeladditionalcountry", + unique_together=set([("country", "utility_model")]), ), ] diff --git a/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py b/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py index 680fa3c0ac..86a3cf7465 100644 --- a/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py +++ b/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py @@ -5,34 +5,33 @@ class Migration(migrations.Migration): - dependencies = [ - ('trade_marks', '0015_auto_20221020_1340'), + ("trade_marks", "0015_auto_20221020_1340"), ] operations = [ migrations.AlterModelManagers( - name='design', + name="design", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='patent', + name="patent", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='trademark', + name="trademark", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='utilitymodel', + name="utilitymodel", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/trade_marks/models.py b/src/ralph/trade_marks/models.py index a5c042ee70..27cc74d4e0 100644 --- a/src/ralph/trade_marks/models.py +++ b/src/ralph/trade_marks/models.py @@ -7,71 +7,58 @@ from ralph.assets.models import AssetHolder, BaseObject from ralph.attachments.helpers import get_file_path from ralph.domains.models import Domain -from ralph.lib.mixins.models import ( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin -) +from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin def verbose_names(**kwargs): def wrap(cls): for field, value in kwargs.items(): - setattr(cls._meta.get_field(field), 'verbose_name', value) + setattr(cls._meta.get_field(field), "verbose_name", value) return cls + return wrap def upload_dir(filename, instance): - return get_file_path( - filename, instance, default_dir="trade_marks" - ) + return get_file_path(filename, instance, default_dir="trade_marks") class ProviderAdditionalMarking( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model + AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model ): """ This class is needed for additional_marking checkbox field. Additional_marking field is for additional services from trade mark register site. """ + pass class TradeMarkStatus(Choices): _ = Choices.Choice - application_filed = _('Application filed') - application_refused = _('Application refused') - application_withdrawn = _('Application withdrawn') - application_opposed = _('Application opposed') - registered = _('Registered') - registration_invalidated = _('Registration invalidated') - registration_expired = _('Registration expired') + application_filed = _("Application filed") + application_refused = _("Application refused") + application_withdrawn = _("Application withdrawn") + application_opposed = _("Application opposed") + registered = _("Registered") + registration_invalidated = _("Registration invalidated") + registration_expired = _("Registration expired") class TradeMarkRegistrarInstitution( - AdminAbsoluteUrlMixin, - NamedMixin.NonUnique, - TimeStampMixin, - models.Model + AdminAbsoluteUrlMixin, NamedMixin.NonUnique, TimeStampMixin, models.Model ): pass -class TradeMarkCountry( - AdminAbsoluteUrlMixin, - models.Model -): +class TradeMarkCountry(AdminAbsoluteUrlMixin, models.Model): country = models.PositiveIntegerField( - verbose_name=_('trade mark country'), + verbose_name=_("trade mark country"), choices=Country(), default=Country.pl.id, null=True, - blank=True + blank=True, ) def __str__(self): @@ -87,16 +74,8 @@ class IntellectualPropertyBase(models.Model): blank=False, max_length=255, ) - number = models.CharField( - blank=False, - null=False, - max_length=255 - ) - image = models.ImageField( - null=True, - blank=True, - upload_to=upload_dir - ) + number = models.CharField(blank=False, null=False, max_length=255) + image = models.ImageField(null=True, blank=True, upload_to=upload_dir) classes = models.CharField( blank=False, null=False, @@ -106,48 +85,45 @@ class IntellectualPropertyBase(models.Model): valid_to = models.DateField(null=True, blank=True) business_owner = models.ForeignKey( settings.AUTH_USER_MODEL, - related_name='%(class)s_business_owner', + related_name="%(class)s_business_owner", blank=False, null=False, - on_delete=models.CASCADE + on_delete=models.CASCADE, ) technical_owner = models.ForeignKey( settings.AUTH_USER_MODEL, - related_name='%(class)s_technical_owner', + related_name="%(class)s_technical_owner", blank=False, null=False, - on_delete=models.CASCADE + on_delete=models.CASCADE, ) order_number_url = models.URLField( - max_length=255, blank=True, null=True, + max_length=255, + blank=True, + null=True, ) additional_markings = models.ManyToManyField( ProviderAdditionalMarking, blank=True, ) holder = models.ForeignKey( - AssetHolder, - blank=True, - null=True, - on_delete=models.CASCADE + AssetHolder, blank=True, null=True, on_delete=models.CASCADE ) status = models.PositiveIntegerField( - choices=TradeMarkStatus(), - default=TradeMarkStatus.registered.id + choices=TradeMarkStatus(), default=TradeMarkStatus.registered.id ) registrar_institution = models.ForeignKey( - TradeMarkRegistrarInstitution, - null=True, - on_delete=models.CASCADE + TradeMarkRegistrarInstitution, null=True, on_delete=models.CASCADE ) database_link = models.URLField( - max_length=255, blank=True, null=True, + max_length=255, + blank=True, + null=True, ) def __str__(self): - return '{}, {}, {} expires {}.'.format( - self.name, self.number, - self.classes, self.valid_to + return "{}, {}, {} expires {}.".format( + self.name, self.number, self.classes, self.valid_to ) class Meta: @@ -163,41 +139,42 @@ def __str__(self): @verbose_names( - name=_('Trade Mark Name'), number=_('Trade Mark number'), - status=_('Trade Mark status'), holder=_('Trade Mark holder'), - image=_('Representation') + name=_("Trade Mark Name"), + number=_("Trade Mark number"), + status=_("Trade Mark status"), + holder=_("Trade Mark holder"), + image=_("Representation"), ) class TradeMark(IntellectualPropertyBase, AdminAbsoluteUrlMixin, BaseObject): type = models.ForeignKey( TradeMarkKind, - verbose_name=_('Trade Mark type'), - related_name='trademarks', + verbose_name=_("Trade Mark type"), + related_name="trademarks", on_delete=models.DO_NOTHING, default=2, ) domains = models.ManyToManyField( Domain, - related_name='+', - through='TradeMarksLinkedDomains', + related_name="+", + through="TradeMarksLinkedDomains", ) class TradeMarksLinkedDomains(models.Model): trade_mark = models.ForeignKey(TradeMark, on_delete=models.CASCADE) domain = models.ForeignKey( - Domain, - related_name='trade_mark', - on_delete=models.CASCADE + Domain, related_name="trade_mark", on_delete=models.CASCADE ) class Meta: - unique_together = ('trade_mark', 'domain') - verbose_name = _('Trade Marks Linked Domain') - verbose_name_plural = _('Trade Marks Linked Domains') + unique_together = ("trade_mark", "domain") + verbose_name = _("Trade Marks Linked Domain") + verbose_name_plural = _("Trade Marks Linked Domains") def __str__(self): - return '{} assigned to {}'.format( - self.trade_mark, self.domain, + return "{} assigned to {}".format( + self.trade_mark, + self.domain, ) @@ -206,39 +183,39 @@ class TradeMarkAdditionalCountry(models.Model): country = models.ForeignKey(TradeMarkCountry, on_delete=models.CASCADE) class Meta: - verbose_name = _('Trade Mark Additional Country') - verbose_name_plural = _('Trade Mark Additional Countries') - unique_together = ('country', 'trade_mark') + verbose_name = _("Trade Mark Additional Country") + verbose_name_plural = _("Trade Mark Additional Countries") + unique_together = ("country", "trade_mark") @verbose_names( - name=_('Patent Name'), number=_('Patent number'), status=_('Patent status'), - holder=_('Patent holder'), image=_('Representation') + name=_("Patent Name"), + number=_("Patent number"), + status=_("Patent status"), + holder=_("Patent holder"), + image=_("Representation"), ) class Patent(IntellectualPropertyBase, AdminAbsoluteUrlMixin, BaseObject): domains = models.ManyToManyField( Domain, - related_name='+', - through='PatentsLinkedDomains', + related_name="+", + through="PatentsLinkedDomains", ) class PatentsLinkedDomains(models.Model): patent = models.ForeignKey(Patent, on_delete=models.CASCADE) - domain = models.ForeignKey( - Domain, - related_name='patent', - on_delete=models.CASCADE - ) + domain = models.ForeignKey(Domain, related_name="patent", on_delete=models.CASCADE) class Meta: - unique_together = ('patent', 'domain') - verbose_name = _('Patent Linked Domain') - verbose_name_plural = _('Patent Linked Domains') + unique_together = ("patent", "domain") + verbose_name = _("Patent Linked Domain") + verbose_name_plural = _("Patent Linked Domains") def __str__(self): - return '{} assigned to {}'.format( - self.patent, self.domain, + return "{} assigned to {}".format( + self.patent, + self.domain, ) @@ -247,39 +224,39 @@ class PatentAdditionalCountry(models.Model): country = models.ForeignKey(TradeMarkCountry, on_delete=models.CASCADE) class Meta: - verbose_name = _('Patent Additional Country') - verbose_name_plural = _('Patent Additional Countries') - unique_together = ('country', 'patent') + verbose_name = _("Patent Additional Country") + verbose_name_plural = _("Patent Additional Countries") + unique_together = ("country", "patent") @verbose_names( - name=_('Design Name'), number=_('Design number'), status=_('Design status'), - holder=_('Design holder'), image=_('Representation') + name=_("Design Name"), + number=_("Design number"), + status=_("Design status"), + holder=_("Design holder"), + image=_("Representation"), ) class Design(IntellectualPropertyBase, AdminAbsoluteUrlMixin, BaseObject): domains = models.ManyToManyField( Domain, - related_name='+', - through='DesignsLinkedDomains', + related_name="+", + through="DesignsLinkedDomains", ) class DesignsLinkedDomains(models.Model): design = models.ForeignKey(Design, on_delete=models.CASCADE) - domain = models.ForeignKey( - Domain, - related_name='design', - on_delete=models.CASCADE - ) + domain = models.ForeignKey(Domain, related_name="design", on_delete=models.CASCADE) class Meta: - unique_together = ('design', 'domain') - verbose_name = _('Design Linked Domain') - verbose_name_plural = _('Design Linked Domains') + unique_together = ("design", "domain") + verbose_name = _("Design Linked Domain") + verbose_name_plural = _("Design Linked Domains") def __str__(self): - return '{} assigned to {}'.format( - self.design, self.domain, + return "{} assigned to {}".format( + self.design, + self.domain, ) @@ -288,15 +265,18 @@ class DesignAdditionalCountry(models.Model): country = models.ForeignKey(TradeMarkCountry, on_delete=models.CASCADE) class Meta: - verbose_name = _('Design Additional Country') - verbose_name_plural = _('Design Additional Countries') - unique_together = ('country', 'design') + verbose_name = _("Design Additional Country") + verbose_name_plural = _("Design Additional Countries") + unique_together = ("country", "design") @verbose_names( - name=_('Utility Model Name'), number=_('Utility Model number'), - status=_('Utility Model status'), holder=_('Utility Model holder'), - image=_('Representation'), classes=_('IPC Classification') + name=_("Utility Model Name"), + number=_("Utility Model number"), + status=_("Utility Model status"), + holder=_("Utility Model holder"), + image=_("Representation"), + classes=_("IPC Classification"), ) class UtilityModel(IntellectualPropertyBase, AdminAbsoluteUrlMixin, BaseObject): pass @@ -307,25 +287,24 @@ class UtilityModelAdditionalCountry(models.Model): country = models.ForeignKey(TradeMarkCountry, on_delete=models.CASCADE) class Meta: - verbose_name = _('Utility Model Additional Country') - verbose_name_plural = _('Utility Model Additional Countries') - unique_together = ('country', 'utility_model') + verbose_name = _("Utility Model Additional Country") + verbose_name_plural = _("Utility Model Additional Countries") + unique_together = ("country", "utility_model") class UtilityModelLinkedDomains(models.Model): utility_model = models.ForeignKey(UtilityModel, on_delete=models.CASCADE) domain = models.ForeignKey( - Domain, - related_name='utility_model', - on_delete=models.CASCADE + Domain, related_name="utility_model", on_delete=models.CASCADE ) class Meta: - unique_together = ('utility_model', 'domain') - verbose_name = _('Utility Model Linked Domain') - verbose_name_plural = _('Utility Model Linked Domains') + unique_together = ("utility_model", "domain") + verbose_name = _("Utility Model Linked Domain") + verbose_name_plural = _("Utility Model Linked Domains") def __str__(self): - return '{} assigned to {}'.format( - self.utility_model, self.domain, + return "{} assigned to {}".format( + self.utility_model, + self.domain, ) diff --git a/src/ralph/trade_marks/tests/factories.py b/src/ralph/trade_marks/tests/factories.py index 6dcdd3f150..c670af80a7 100644 --- a/src/ralph/trade_marks/tests/factories.py +++ b/src/ralph/trade_marks/tests/factories.py @@ -18,7 +18,7 @@ TradeMarkRegistrarInstitution, TradeMarksLinkedDomains, UtilityModel, - UtilityModelLinkedDomains + UtilityModelLinkedDomains, ) date_now = datetime.now().date() @@ -26,11 +26,11 @@ class TradeMarkFactory(DjangoModelFactory): valid_to = date_now + timedelta(days=365) - number = factory.Sequence(lambda n: 'Registrant number ' + str(n)) - name = factory.Sequence(lambda n: 'Trade Mark name ' + str(n)) + number = factory.Sequence(lambda n: "Registrant number " + str(n)) + name = factory.Sequence(lambda n: "Trade Mark name " + str(n)) technical_owner = factory.SubFactory(UserFactory) business_owner = factory.SubFactory(UserFactory) - classes = factory.Sequence(lambda n: 'Registrant class ' + str(n)) + classes = factory.Sequence(lambda n: "Registrant class " + str(n)) holder = factory.SubFactory(AssetHolderFactory) class Meta: @@ -39,11 +39,11 @@ class Meta: class PatentFactory(DjangoModelFactory): valid_to = date_now + timedelta(days=365) - number = factory.Sequence(lambda n: 'Registrant number ' + str(n)) - name = factory.Sequence(lambda n: 'Patent name ' + str(n)) + number = factory.Sequence(lambda n: "Registrant number " + str(n)) + name = factory.Sequence(lambda n: "Patent name " + str(n)) technical_owner = factory.SubFactory(UserFactory) business_owner = factory.SubFactory(UserFactory) - classes = factory.Sequence(lambda n: 'Registrant class ' + str(n)) + classes = factory.Sequence(lambda n: "Registrant class " + str(n)) holder = factory.SubFactory(AssetHolderFactory) class Meta: @@ -52,11 +52,11 @@ class Meta: class DesignFactory(DjangoModelFactory): valid_to = date_now + timedelta(days=365) - number = factory.Sequence(lambda n: 'Registrant number ' + str(n)) - name = factory.Sequence(lambda n: 'Design name ' + str(n)) + number = factory.Sequence(lambda n: "Registrant number " + str(n)) + name = factory.Sequence(lambda n: "Design name " + str(n)) technical_owner = factory.SubFactory(UserFactory) business_owner = factory.SubFactory(UserFactory) - classes = factory.Sequence(lambda n: 'Registrant class ' + str(n)) + classes = factory.Sequence(lambda n: "Registrant class " + str(n)) holder = factory.SubFactory(AssetHolderFactory) class Meta: @@ -64,11 +64,11 @@ class Meta: class TradeMarkRegistrarInstitutionFactory(DjangoModelFactory): - name = factory.Iterator(['WNIP', 'WIP', 'PUP']) + name = factory.Iterator(["WNIP", "WIP", "PUP"]) class Meta: model = TradeMarkRegistrarInstitution - django_get_or_create = ['name'] + django_get_or_create = ["name"] class TradeMarkCountryFactory(DjangoModelFactory): @@ -87,11 +87,11 @@ class Meta: class ProviderAdditionalMarkingFactory(DjangoModelFactory): - name = factory.Iterator(['Masking', 'Backside', 'Acquisition']) + name = factory.Iterator(["Masking", "Backside", "Acquisition"]) class Meta: model = ProviderAdditionalMarking - django_get_or_create = ['name'] + django_get_or_create = ["name"] class TradeMarkAdditionalCountryFactory(DjangoModelFactory): @@ -104,11 +104,11 @@ class Meta: class UtilityModelFactory(DjangoModelFactory): valid_to = date_now + timedelta(days=365) - number = factory.Sequence(lambda n: 'Registrant number ' + str(n)) - name = factory.Sequence(lambda n: 'Trade Mark name ' + str(n)) + number = factory.Sequence(lambda n: "Registrant number " + str(n)) + name = factory.Sequence(lambda n: "Trade Mark name " + str(n)) technical_owner = factory.SubFactory(UserFactory) business_owner = factory.SubFactory(UserFactory) - classes = factory.Sequence(lambda n: 'Registrant class ' + str(n)) + classes = factory.Sequence(lambda n: "Registrant class " + str(n)) holder = factory.SubFactory(AssetHolderFactory) class Meta: diff --git a/src/ralph/urls/__init__.py b/src/ralph/urls/__init__.py index cec495b120..7ddaa0a60c 100644 --- a/src/ralph/urls/__init__.py +++ b/src/ralph/urls/__init__.py @@ -1,4 +1,4 @@ from ralph.urls.base import urlpatterns # noqa -handler404 = 'ralph.lib.error_pages.views.page_not_found' +handler404 = "ralph.lib.error_pages.views.page_not_found" diff --git a/src/ralph/urls/base.py b/src/ralph/urls/base.py index 056a3e72ba..41deafed50 100644 --- a/src/ralph/urls/base.py +++ b/src/ralph/urls/base.py @@ -15,59 +15,64 @@ # import custom urls from each api module # notice that each module should have `urlpatters` variable defined # (as empty list if there is any custom url) -api_urls = list(map(lambda u: url(r'^', include(u)), [ - 'ralph.access_cards.api', - 'ralph.accounts.api', - 'ralph.assets.api.routers', - 'ralph.back_office.api', - 'ralph.configuration_management.api', - 'ralph.dashboards.api.routers', - 'ralph.data_center.api.routers', - 'ralph.dc_view.urls.api', - 'ralph.dhcp.api', - 'ralph.domains.api', - 'ralph.operations.api', - 'ralph.supports.api', - 'ralph.security.api', - 'ralph.sim_cards.api', - 'ralph.ssl_certificates.api', - 'ralph.networks.api', - 'ralph.virtual.api', - 'ralph.lib.custom_fields.api.custom_fields_api', - 'ralph.lib.transitions.api.routers', -])) +api_urls = list( + map( + lambda u: url(r"^", include(u)), + [ + "ralph.access_cards.api", + "ralph.accounts.api", + "ralph.assets.api.routers", + "ralph.back_office.api", + "ralph.configuration_management.api", + "ralph.dashboards.api.routers", + "ralph.data_center.api.routers", + "ralph.dc_view.urls.api", + "ralph.dhcp.api", + "ralph.domains.api", + "ralph.operations.api", + "ralph.supports.api", + "ralph.security.api", + "ralph.sim_cards.api", + "ralph.ssl_certificates.api", + "ralph.networks.api", + "ralph.virtual.api", + "ralph.lib.custom_fields.api.custom_fields_api", + "ralph.lib.transitions.api.routers", + ], + ) +) # include router urls # because we're using single router instance and urls are cached inside this # object, router.urls may be called after all urls are processed (and all # api views are registered in router) -api_urls += [url(r'^', include(router.urls))] +api_urls += [url(r"^", include(router.urls))] urlpatterns = [ - url(r'^', admin.urls), - url(r'^api/', include(api_urls)), - url(r'^api-token-auth/', views.obtain_auth_token), - url(r'^', include('ralph.dc_view.urls.ui')), - url(r'^', include('ralph.attachments.urls')), - url(r'^', include('ralph.dashboards.urls')), - url(r'^', include('ralph.accounts.urls')), - url(r'^', include('ralph.reports.urls')), - url(r'^', include('ralph.admin.autocomplete_urls')), - url(r'^dhcp/', include('ralph.dhcp.urls')), - url(r'^deployment/', include('ralph.deployment.urls')), - url(r'^virtual/', include('ralph.virtual.urls')), - url(r'^', include('ralph.lib.transitions.urls')), - url(r'^i18n/', include('django.conf.urls.i18n')), + url(r"^", admin.urls), + url(r"^api/", include(api_urls)), + url(r"^api-token-auth/", views.obtain_auth_token), + url(r"^", include("ralph.dc_view.urls.ui")), + url(r"^", include("ralph.attachments.urls")), + url(r"^", include("ralph.dashboards.urls")), + url(r"^", include("ralph.accounts.urls")), + url(r"^", include("ralph.reports.urls")), + url(r"^", include("ralph.admin.autocomplete_urls")), + url(r"^dhcp/", include("ralph.dhcp.urls")), + url(r"^deployment/", include("ralph.deployment.urls")), + url(r"^virtual/", include("ralph.virtual.urls")), + url(r"^", include("ralph.lib.transitions.urls")), + url(r"^i18n/", include("django.conf.urls.i18n")), url( - r'^status/ping?$', + r"^status/ping?$", status_ping, - name='status-ping', + name="status-ping", ), url( - r'^status/health?$', + r"^status/health?$", status_health, - name='status-health', + name="status-health", ), ] -if getattr(settings, 'ENABLE_HERMES_INTEGRATION', False): - urlpatterns += url(r'^hermes/', include('pyhermes.apps.django.urls')), +if getattr(settings, "ENABLE_HERMES_INTEGRATION", False): + urlpatterns += (url(r"^hermes/", include("pyhermes.apps.django.urls")),) diff --git a/src/ralph/urls/dev.py b/src/ralph/urls/dev.py index 407d076772..f7f7c7a433 100644 --- a/src/ralph/urls/dev.py +++ b/src/ralph/urls/dev.py @@ -9,10 +9,8 @@ urlpatterns = base_urlpatterns urlpatterns += [ - url(r'^__debug__/', include(debug_toolbar.urls)), + url(r"^__debug__/", include(debug_toolbar.urls)), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -if 'silk' in settings.INSTALLED_APPS: - urlpatterns += [ - url(r'^silk/', include('silk.urls', namespace='silk')) - ] +if "silk" in settings.INSTALLED_APPS: + urlpatterns += [url(r"^silk/", include("silk.urls", namespace="silk"))] diff --git a/src/ralph/urls/test.py b/src/ralph/urls/test.py index 98df82de2b..8ca218fe1c 100644 --- a/src/ralph/urls/test.py +++ b/src/ralph/urls/test.py @@ -4,15 +4,14 @@ from ralph.api.tests import api as ralph_api from ralph.lib.custom_fields.tests import urls as custom_fields_tests_urls from ralph.lib.permissions.tests import api as lib_api -from ralph.lib.permissions.tests.test_permission_view import \ - urls as perm_view_url # noqa +from ralph.lib.permissions.tests.test_permission_view import urls as perm_view_url # noqa from ralph.urls.base import urlpatterns as base_urlpatterns urlpatterns = base_urlpatterns urlpatterns += [ - url(r'^', include(lib_api.urlpatterns)), - url(r'^', include(perm_view_url)), - url(r'^', include(ralph_api.urlpatterns)), - url(r'^', include(custom_fields_tests_urls.urlpatterns)), + url(r"^", include(lib_api.urlpatterns)), + url(r"^", include(perm_view_url)), + url(r"^", include(ralph_api.urlpatterns)), + url(r"^", include(custom_fields_tests_urls.urlpatterns)), ] diff --git a/src/ralph/virtual/admin.py b/src/ralph/virtual/admin.py index 4ae4f6aebc..8e0f092228 100644 --- a/src/ralph/virtual/admin.py +++ b/src/ralph/virtual/admin.py @@ -15,7 +15,7 @@ from ralph.assets.views import ComponentsAdminView, RalphDetailViewAdmin from ralph.configuration_management.views import ( SCMCheckInfo, - SCMStatusCheckInChangeListMixin + SCMStatusCheckInChangeListMixin, ) from ralph.data_center.admin import generate_list_filter_with_common_fields from ralph.data_center.models.physical import DataCenterAsset @@ -35,7 +35,7 @@ CloudProject, CloudProvider, VirtualServer, - VirtualServerType + VirtualServerType, ) if settings.ENABLE_DNSAAS_INTEGRATION: @@ -46,11 +46,11 @@ class VirtualServerDNSView(DNSView): class VirtaulServerSecurityInfoView(SecurityInfo): - url_name = 'security_virtualserver_security_info' + url_name = "security_virtualserver_security_info" class CloudHostSecurityInfoView(SecurityInfo): - url_name = 'security_cloudhost_security_info' + url_name = "security_cloudhost_security_info" @register(VirtualServerType) @@ -60,29 +60,28 @@ class VirtualServerTypeForm(RalphAdmin): class VirtualServerForm(RalphAdminForm): HYPERVISOR_TYPE_ERR_MSG = _( - 'Hypervisor must be one of DataCenterAsset or CloudHost' + "Hypervisor must be one of DataCenterAsset or CloudHost" ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if 'parent' in self.fields: - self.fields['parent'].required = True + if "parent" in self.fields: + self.fields["parent"].required = True def clean_parent(self): - value = self.cleaned_data.get('parent') + value = self.cleaned_data.get("parent") self._validate_parent_type(value) return value def _validate_parent_type(self, value): allowed_types = ContentType.objects.get_for_models( - DataCenterAsset, - CloudHost + DataCenterAsset, CloudHost ).values() if value.content_type not in allowed_types: raise ValidationError(self.HYPERVISOR_TYPE_ERR_MSG) class Meta: - labels = {'parent': _('Hypervisor')} + labels = {"parent": _("Hypervisor")} class VirtualServerNetworkView(NetworkView): @@ -94,21 +93,21 @@ class VirtualServerComponentsView(ComponentsAdminView): class VirtualServerLicencesView(RalphDetailViewAdmin): - icon = 'key' - name = 'virtual_licences' - label = _('Licences') - url_name = 'licences' + icon = "key" + name = "virtual_licences" + label = _("Licences") + url_name = "licences" class VirtualServerLicenceInline(RalphTabularInline): model = BaseObjectLicence - raw_id_fields = ('licence',) + raw_id_fields = ("licence",) extra = 1 inlines = [VirtualServerLicenceInline] class VirtualServerSCMInfo(SCMCheckInfo): - url_name = 'virtualserver_scm_info' + url_name = "virtualserver_scm_info" @register(VirtualServer) @@ -118,28 +117,42 @@ class VirtualServerAdmin( ActiveDeploymentMessageMixin, CustomFieldValueAdminMixin, TransitionAdminMixin, - RalphAdmin + RalphAdmin, ): form = VirtualServerForm - search_fields = ['hostname', 'sn', 'ethernet_set__ipaddress__hostname'] + search_fields = ["hostname", "sn", "ethernet_set__ipaddress__hostname"] list_filter_prefix = [BaseObjectHostnameFilter] - list_filter_postfix = ['sn', 'parent', TagsListFilter] + list_filter_postfix = ["sn", "parent", TagsListFilter] list_filter = generate_list_filter_with_common_fields( - list_filter_prefix, - list_filter_postfix + list_filter_prefix, list_filter_postfix ) list_display = [ - 'hostname', 'type', 'sn', 'service_env', 'configuration_path', - 'parent_', 'scan_status', 'scm_status_check' + "hostname", + "type", + "sn", + "service_env", + "configuration_path", + "parent_", + "scan_status", + "scm_status_check", ] - raw_id_fields = ['parent', 'service_env', 'configuration_path'] + raw_id_fields = ["parent", "service_env", "configuration_path"] fields = [ - 'hostname', 'type', 'status', 'sn', 'service_env', - 'configuration_path', 'parent', 'remarks', 'tags' + "hostname", + "type", + "status", + "sn", + "service_env", + "configuration_path", + "parent", + "remarks", + "tags", ] list_select_related = [ - 'service_env__service', 'service_env__environment', 'type', - 'configuration_path__module', + "service_env__service", + "service_env__environment", + "type", + "configuration_path__module", ] change_views = [ @@ -157,20 +170,17 @@ class VirtualServerAdmin( # TODO: add the same tabs as in DCAsset class ClusterBaseObjectInline(RalphTabularInline): model = BaseObjectCluster - fk_name = 'base_object' - raw_id_fields = ('cluster',) + fk_name = "base_object" + raw_id_fields = ("cluster",) extra = 1 - verbose_name = _('Base Object') + verbose_name = _("Base Object") inlines = [ClusterBaseObjectInline] def get_queryset(self, request): qs = super().get_queryset(request) return qs.prefetch_related( - Prefetch( - 'parent', - queryset=BaseObject.polymorphic_objects.all() - ), + Prefetch("parent", queryset=BaseObject.polymorphic_objects.all()), ) @mark_safe @@ -181,65 +191,75 @@ def parent_(self, obj): parent.get_absolute_url(), parent.hostname ) except: # noqa # this happens when no parent or parent doesn't have a hostname - return '-' + return "-" class CloudHostTabularInline(RalphTabularInline): can_delete = False model = CloudHost - fk_name = 'parent' - fields = ['get_hostname', 'get_hypervisor', 'get_ip_addresses', 'created', - 'tags', 'remarks'] + fk_name = "parent" + fields = [ + "get_hostname", + "get_hypervisor", + "get_ip_addresses", + "created", + "tags", + "remarks", + ] readonly_fields = fields @mark_safe def get_hostname(self, obj): return '{}'.format( - reverse("admin:virtual_cloudhost_change", args=(obj.id,)), - obj.hostname + reverse("admin:virtual_cloudhost_change", args=(obj.id,)), obj.hostname ) - get_hostname.short_description = _('Hostname') + + get_hostname.short_description = _("Hostname") @mark_safe def get_hypervisor(self, obj): if obj.hypervisor is None: - return _('Not set') + return _("Not set") return '{}'.format( reverse( - "admin:data_center_datacenterasset_change", - args=(obj.hypervisor.id,) + "admin:data_center_datacenterasset_change", args=(obj.hypervisor.id,) ), - obj.hypervisor.hostname + obj.hypervisor.hostname, ) - get_hypervisor.short_description = _('Hypervisor') + + get_hypervisor.short_description = _("Hypervisor") @mark_safe def get_ip_addresses(self, obj): - ips = obj.ethernet_set.values_list( - 'ipaddress__address', flat=True - ) + ips = obj.ethernet_set.values_list("ipaddress__address", flat=True) if not ips: - return '–' - return '\n'.join(ips) - get_ip_addresses.short_description = _('IP Addresses') + return "–" + return "\n".join(ips) + + get_ip_addresses.short_description = _("IP Addresses") def has_add_permission(self, request, obj=None): return False def get_queryset(self, *args, **kwargs): - return super().get_queryset(*args, **kwargs).select_related( - 'hypervisor', - ).prefetch_related('tags') + return ( + super() + .get_queryset(*args, **kwargs) + .select_related( + "hypervisor", + ) + .prefetch_related("tags") + ) class CloudHostNetworkForm(SimpleNetworkForm): class Meta(SimpleNetworkForm.Meta): - fields = ['address', 'hostname'] + fields = ["address", "hostname"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - for field in ['address', 'hostname']: - self.fields[field].widget.attrs['readonly'] = True + for field in ["address", "hostname"]: + self.fields[field].widget.attrs["readonly"] = True class CloudNetworkInline(RalphTabularInline): @@ -256,65 +276,108 @@ class CloudHostNetworkView(NetworkView): class CloudHostSCMInfo(SCMCheckInfo): - url_name = 'cloudhost_scm_info' + url_name = "cloudhost_scm_info" @register(CloudHost) class CloudHostAdmin( - SCMStatusCheckInChangeListMixin, ScanStatusInChangeListMixin, - CustomFieldValueAdminMixin, RalphAdmin + SCMStatusCheckInChangeListMixin, + ScanStatusInChangeListMixin, + CustomFieldValueAdminMixin, + RalphAdmin, ): - list_display = ['get_hostname', 'get_ip_addresses', 'service_env', - 'get_cloudproject', 'cloudflavor_name', 'host_id', - 'created', 'image_name', 'get_tags', 'scan_status', - 'scm_status_check'] - list_filter_prefix = [BaseObjectHostnameFilter] - list_filter_postfix = [ - 'cloudprovider', 'cloudflavor', TagsListFilter, 'hypervisor' + list_display = [ + "get_hostname", + "get_ip_addresses", + "service_env", + "get_cloudproject", + "cloudflavor_name", + "host_id", + "created", + "image_name", + "get_tags", + "scan_status", + "scm_status_check", ] + list_filter_prefix = [BaseObjectHostnameFilter] + list_filter_postfix = ["cloudprovider", "cloudflavor", TagsListFilter, "hypervisor"] list_filter = generate_list_filter_with_common_fields( - list_filter_prefix, - list_filter_postfix + list_filter_prefix, list_filter_postfix ) list_select_related = [ - 'cloudflavor', 'cloudprovider', 'parent__cloudproject', - 'service_env__service', 'service_env__environment' + "cloudflavor", + "cloudprovider", + "parent__cloudproject", + "service_env__service", + "service_env__environment", + ] + readonly_fields = [ + "cloudflavor_name", + "created", + "hostname", + "host_id", + "get_cloudproject", + "get_cloudprovider", + "get_service", + "get_cpu", + "get_disk", + "get_hypervisor", + "get_memory", + "modified", + "parent", + "service_env", + "image_name", + "get_configuration_path", ] - readonly_fields = ['cloudflavor_name', 'created', 'hostname', 'host_id', - 'get_cloudproject', 'get_cloudprovider', 'get_service', - 'get_cpu', 'get_disk', 'get_hypervisor', 'get_memory', - 'modified', 'parent', 'service_env', 'image_name', - 'get_configuration_path'] search_fields = [ - 'cloudflavor__name', 'host_id', - 'hostname', 'ethernet_set__ipaddress__hostname' + "cloudflavor__name", + "host_id", + "hostname", + "ethernet_set__ipaddress__hostname", ] - raw_id_override_parent = {'parent': CloudProject} + raw_id_override_parent = {"parent": CloudProject} inlines = [CloudNetworkInline] - change_views = [ - CloudHostNetworkView, - CloudHostSCMInfo, - CloudHostSecurityInfoView - ] + change_views = [CloudHostNetworkView, CloudHostSCMInfo, CloudHostSecurityInfoView] fieldsets = ( - (None, { - 'fields': ['hostname', 'get_hypervisor', 'host_id', 'created', - 'get_cloudprovider', 'tags', 'remarks'] - }), - ('Cloud Project', { - 'fields': ['get_cloudproject', 'get_service', - 'get_configuration_path'], - }), - ('Components', { - 'fields': ['cloudflavor_name', 'get_cpu', 'get_memory', 'get_disk', - 'image_name'] - }), + ( + None, + { + "fields": [ + "hostname", + "get_hypervisor", + "host_id", + "created", + "get_cloudprovider", + "tags", + "remarks", + ] + }, + ), + ( + "Cloud Project", + { + "fields": ["get_cloudproject", "get_service", "get_configuration_path"], + }, + ), + ( + "Components", + { + "fields": [ + "cloudflavor_name", + "get_cpu", + "get_memory", + "get_disk", + "image_name", + ] + }, + ), ) def get_queryset(self, request): - return super().get_queryset(request).prefetch_related( - 'tags', - 'ethernet_set__ipaddress' + return ( + super() + .get_queryset(request) + .prefetch_related("tags", "ethernet_set__ipaddress") ) def has_delete_permission(self, request, obj=None): @@ -322,204 +385,245 @@ def has_delete_permission(self, request, obj=None): # additional list and details fields def get_tags(self, obj): - return ', '.join([tag.name for tag in obj.tags.all()]) - get_tags.short_description = _('Tags') + return ", ".join([tag.name for tag in obj.tags.all()]) + + get_tags.short_description = _("Tags") def get_cloudprovider(self, obj): return obj.cloudprovider.name - get_cloudprovider.short_description = _('Cloud provider') - get_cloudprovider.admin_order_field = 'cloudprovider__name' + + get_cloudprovider.short_description = _("Cloud provider") + get_cloudprovider.admin_order_field = "cloudprovider__name" def get_hostname(self, obj): - return obj.hostname if len(obj.hostname) > 1 else '–' + return obj.hostname if len(obj.hostname) > 1 else "–" - get_hostname.short_description = _('Hostname') + get_hostname.short_description = _("Hostname") @mark_safe def get_hypervisor(self, obj): if obj.hypervisor is None: - return _('Not set') + return _("Not set") return '{}'.format( - reverse("admin:data_center_datacenterasset_change", - args=(obj.hypervisor.id,)), - obj.hypervisor.hostname + reverse( + "admin:data_center_datacenterasset_change", args=(obj.hypervisor.id,) + ), + obj.hypervisor.hostname, ) - get_hypervisor.short_description = _('Hypervisor') - get_hypervisor.admin_order_field = 'hypervisor__hostname' + + get_hypervisor.short_description = _("Hypervisor") + get_hypervisor.admin_order_field = "hypervisor__hostname" @mark_safe def cloudflavor_name(self, obj): return '{}'.format( - reverse("admin:virtual_cloudflavor_change", - args=(obj.cloudflavor.id,)), - obj.cloudflavor.name + reverse("admin:virtual_cloudflavor_change", args=(obj.cloudflavor.id,)), + obj.cloudflavor.name, ) - cloudflavor_name.short_description = _('Cloud Flavor') - cloudflavor_name.admin_order_field = 'cloudflavor__name' + + cloudflavor_name.short_description = _("Cloud Flavor") + cloudflavor_name.admin_order_field = "cloudflavor__name" @mark_safe def get_ip_addresses(self, obj): - ips = [ - eth.ipaddress.address - for eth in obj.ethernet_set.all() - if eth.ipaddress - ] + ips = [eth.ipaddress.address for eth in obj.ethernet_set.all() if eth.ipaddress] if not ips: - return '–' - return '\n'.join(ips) - get_ip_addresses.short_description = _('IP Addresses') + return "–" + return "\n".join(ips) + + get_ip_addresses.short_description = _("IP Addresses") @mark_safe def get_cloudproject(self, obj): return '{}'.format( - reverse( - "admin:virtual_cloudproject_change", - args=(obj.parent.id,) - ), - obj.parent.cloudproject.name + reverse("admin:virtual_cloudproject_change", args=(obj.parent.id,)), + obj.parent.cloudproject.name, ) - get_cloudproject.short_description = _('Cloud Project') - get_cloudproject.admin_order_field = 'parent' - get_cloudproject._permission_field = 'parent' + + get_cloudproject.short_description = _("Cloud Project") + get_cloudproject.admin_order_field = "parent" + get_cloudproject._permission_field = "parent" @mark_safe def get_service(self, obj): if obj.service_env_id: return '{}'.format( reverse( - "admin:assets_service_change", - args=(obj.service_env.service_id,) + "admin:assets_service_change", args=(obj.service_env.service_id,) ), - obj.service_env + obj.service_env, ) - return '' - get_service.short_description = _('Service env') - get_service.admin_order_field = 'service_env' - get_service._permission_field = 'service_env' + return "" + + get_service.short_description = _("Service env") + get_service.admin_order_field = "service_env" + get_service._permission_field = "service_env" @mark_safe def get_configuration_path(self, obj): if obj.configuration_path_id: return '{}'.format( reverse( - 'admin:assets_configurationclass_change', - args=[obj.configuration_path_id] + "admin:assets_configurationclass_change", + args=[obj.configuration_path_id], ), - obj.configuration_path + obj.configuration_path, ) - return '' - get_configuration_path.short_description = _('Configuration path') - get_configuration_path._permission_field = 'configuration_path' + return "" + + get_configuration_path.short_description = _("Configuration path") + get_configuration_path._permission_field = "configuration_path" def get_cpu(self, obj): return obj.cloudflavor.cores - get_cpu.short_description = _('vCPU cores') + + get_cpu.short_description = _("vCPU cores") def get_memory(self, obj): return obj.cloudflavor.memory - get_memory.short_description = _('RAM size (MiB)') + + get_memory.short_description = _("RAM size (MiB)") def get_disk(self, obj): return obj.cloudflavor.disk / 1024 if obj.cloudflavor.disk else None - get_disk.short_description = _('Disk size (GiB)') + + get_disk.short_description = _("Disk size (GiB)") @register(CloudFlavor) class CloudFlavorAdmin(RalphAdmin): - list_display = ['name', 'flavor_id', 'cores', 'memory', 'disk', 'get_tags', - 'instances_count'] - search_fields = ['name', 'flavor_id'] - readonly_fields = ['name', 'cloudprovider', 'flavor_id', 'cores', - 'memory', 'disk', 'instances_count'] - list_filter = ['cloudprovider', TagsListFilter] + list_display = [ + "name", + "flavor_id", + "cores", + "memory", + "disk", + "get_tags", + "instances_count", + ] + search_fields = ["name", "flavor_id"] + readonly_fields = [ + "name", + "cloudprovider", + "flavor_id", + "cores", + "memory", + "disk", + "instances_count", + ] + list_filter = ["cloudprovider", TagsListFilter] fieldsets = ( - ('Cloud Flavor', { - 'fields': ['name', 'cloudprovider', 'flavor_id', 'tags', - 'instances_count'] - }), - ('Components', { - 'fields': ['cores', 'memory', 'disk'] - }), + ( + "Cloud Flavor", + { + "fields": [ + "name", + "cloudprovider", + "flavor_id", + "tags", + "instances_count", + ] + }, + ), + ("Components", {"fields": ["cores", "memory", "disk"]}), ) def has_delete_permission(self, request, obj=None): return False def get_queryset(self, request): - return super().get_queryset(request).prefetch_related( - 'virtualcomponent_set__model', 'tags' - ).annotate(instances_count=Count('cloudhost')) + return ( + super() + .get_queryset(request) + .prefetch_related("virtualcomponent_set__model", "tags") + .annotate(instances_count=Count("cloudhost")) + ) def get_tags(self, obj): - return ', '.join([tag.name for tag in obj.tags.all()]) - get_tags.short_description = _('Tags') + return ", ".join([tag.name for tag in obj.tags.all()]) + + get_tags.short_description = _("Tags") def get_cpu(self, obj): return obj.cores - get_cpu.short_description = _('vCPU cores') + + get_cpu.short_description = _("vCPU cores") def get_memory(self, obj): return obj.memory - get_memory.short_description = _('RAM size (MiB)') + + get_memory.short_description = _("RAM size (MiB)") def get_disk(self, obj): return obj.disk / 1024 - get_disk.short_description = _('Disk size (GiB)') + + get_disk.short_description = _("Disk size (GiB)") def instances_count(self, obj): return obj.instances_count - instances_count.short_description = _('instances count') - instances_count.admin_order_field = 'instances_count' + + instances_count.short_description = _("instances count") + instances_count.admin_order_field = "instances_count" @register(CloudProject) class CloudProjectAdmin(CustomFieldValueAdminMixin, RalphAdmin): - fields = ['name', 'project_id', 'cloudprovider', 'service_env', 'tags', - 'remarks', 'instances_count'] - list_display = ['name', 'service_env', 'instances_count'] - list_select_related = ['cloudprovider', - 'service_env__environment', - 'service_env__service'] - list_filter = ['service_env', 'cloudprovider', TagsListFilter] - readonly_fields = ['name', 'project_id', 'cloudprovider', 'created', - 'instances_count'] - search_fields = ['name', 'project_id'] - raw_id_fields = ['service_env'] + fields = [ + "name", + "project_id", + "cloudprovider", + "service_env", + "tags", + "remarks", + "instances_count", + ] + list_display = ["name", "service_env", "instances_count"] + list_select_related = [ + "cloudprovider", + "service_env__environment", + "service_env__service", + ] + list_filter = ["service_env", "cloudprovider", TagsListFilter] + readonly_fields = [ + "name", + "project_id", + "cloudprovider", + "created", + "instances_count", + ] + search_fields = ["name", "project_id"] + raw_id_fields = ["service_env"] inlines = [CloudHostTabularInline] def has_delete_permission(self, request, obj=None): return False def get_queryset(self, request): - return super().get_queryset(request).annotate( - instances_count=Count('children') - ) + return super().get_queryset(request).annotate(instances_count=Count("children")) def get_cloudprovider(self, obj): return obj.cloudprovider.name - get_cloudprovider.short_description = _('Cloud provider') - get_cloudprovider.admin_order_field = 'cloudprovider__name' + + get_cloudprovider.short_description = _("Cloud provider") + get_cloudprovider.admin_order_field = "cloudprovider__name" def instances_count(self, obj): return obj.instances_count - instances_count.short_description = _('instances count') - instances_count.admin_order_field = 'instances_count' + + instances_count.short_description = _("instances count") + instances_count.admin_order_field = "instances_count" @register(CloudProvider) class CloudProviderAdmin(RalphAdmin): form = CloudProviderForm - list_display = ['name', 'cloud_sync_enabled', 'cloud_sync_driver'] - list_filter = ['name', 'cloud_sync_enabled', 'cloud_sync_driver'] + list_display = ["name", "cloud_sync_enabled", "cloud_sync_driver"] + list_filter = ["name", "cloud_sync_enabled", "cloud_sync_driver"] @register(CloudImage) class CloudImageAdmin(RalphAdmin): - list_display = ['name', 'image_id'] - list_filter = ['name'] + list_display = ["name", "image_id"] + list_filter = ["name"] - fieldsets = ( - ('Cloud Image', { - 'fields': ['name', 'image_id'] - }), - ) + fieldsets = (("Cloud Image", {"fields": ["name", "image_id"]}),) diff --git a/src/ralph/virtual/api.py b/src/ralph/virtual/api.py index 60cc6db882..ce7579059b 100644 --- a/src/ralph/virtual/api.py +++ b/src/ralph/virtual/api.py @@ -12,11 +12,11 @@ BaseObjectSerializer, ComponentSerializerMixin, NetworkComponentSerializerMixin, - ServiceEnvironmentSimpleSerializer + ServiceEnvironmentSimpleSerializer, ) from ralph.assets.api.views import ( base_object_descendant_prefetch_related, - BaseObjectViewSetMixin + BaseObjectViewSetMixin, ) from ralph.assets.models import Ethernet from ralph.configuration_management.api import SCMInfoSerializer @@ -33,14 +33,14 @@ CloudProject, CloudProvider, VirtualServer, - VirtualServerType + VirtualServerType, ) class CloudFlavorSimpleSerializer(BaseObjectSerializer): class Meta: model = CloudFlavor - fields = ['name', 'cores', 'memory', 'disk', 'url'] + fields = ["name", "cores", "memory", "disk", "url"] _skip_tags_field = True @@ -49,13 +49,13 @@ class CloudHostSimpleSerializer(BaseObjectSerializer): class Meta: model = CloudHost - fields = ['id', 'hostname', 'ip_addresses', 'url'] + fields = ["id", "hostname", "ip_addresses", "url"] class CloudProjectSimpleSerializer(BaseObjectSerializer): class Meta: model = CloudProject - fields = ['name', 'url', 'project_id'] + fields = ["name", "url", "project_id"] _skip_tags_field = True @@ -67,9 +67,9 @@ class SaveCloudFlavorSerializer(RalphAPISaveSerializer): @transaction.atomic def create(self, validated_data): - cores = validated_data.pop('cores') - memory = validated_data.pop('memory') - disk = validated_data.pop('disk') + cores = validated_data.pop("cores") + memory = validated_data.pop("memory") + disk = validated_data.pop("disk") instance = super().create(validated_data) instance.cores = cores instance.memory = memory @@ -78,7 +78,7 @@ def create(self, validated_data): class Meta: model = CloudFlavor - exclude = ['content_type'] + exclude = ["content_type"] class SaveCloudHostSerializer(RalphAPISaveSerializer): @@ -86,14 +86,14 @@ class SaveCloudHostSerializer(RalphAPISaveSerializer): ip_addresses = serializers.ListField() def create(self, validated_data): - ip_addresses = validated_data.pop('ip_addresses') + ip_addresses = validated_data.pop("ip_addresses") instance = super().create(validated_data) instance.ip_addresses = ip_addresses return instance class Meta: model = CloudHost - exclude = ['content_type'] + exclude = ["content_type"] class CloudFlavorSerializer(BaseObjectSerializer): @@ -104,14 +104,12 @@ class CloudFlavorSerializer(BaseObjectSerializer): class Meta(BaseObjectSerializer.Meta): model = CloudFlavor - exclude = ['content_type', 'service_env', 'parent'] + exclude = ["content_type", "service_env", "parent"] -class CloudHostSerializer( - NetworkComponentSerializerMixin, BaseObjectSerializer -): +class CloudHostSerializer(NetworkComponentSerializerMixin, BaseObjectSerializer): hypervisor = DataCenterAssetSimpleSerializer() - parent = CloudProjectSimpleSerializer(source='cloudproject') + parent = CloudProjectSimpleSerializer(source="cloudproject") cloudflavor = CloudFlavorSimpleSerializer() service_env = ServiceEnvironmentSimpleSerializer() scmstatuscheck = SCMInfoSerializer() @@ -123,12 +121,12 @@ class Meta(BaseObjectSerializer.Meta): class CloudProjectSerializer(BaseObjectSerializer): - cloud_hosts = CloudHostSimpleSerializer(many=True, source='children') + cloud_hosts = CloudHostSimpleSerializer(many=True, source="children") class Meta(BaseObjectSerializer.Meta): model = CloudProject depth = 2 - exclude = ['content_type', 'parent'] + exclude = ["content_type", "parent"] class CloudImageSerializer(RalphAPISerializer): @@ -152,7 +150,7 @@ class Meta: class VirtualServerSimpleSerializer(BaseObjectSerializer): class Meta(BaseObjectSerializer.Meta): model = VirtualServer - fields = ['id', 'hostname', 'url'] + fields = ["id", "hostname", "url"] _skip_tags_field = True exclude = None @@ -160,42 +158,43 @@ class Meta(BaseObjectSerializer.Meta): class VirtualServerSerializer(ComponentSerializerMixin, BaseObjectSerializer): type = VirtualServerTypeSerializer() # TODO: cast BaseObject to DataCenterAsset for hypervisor field - hypervisor = DataCenterAssetSimpleSerializer(source='parent') + hypervisor = DataCenterAssetSimpleSerializer(source="parent") # TODO: clusters scmstatuscheck = SCMInfoSerializer() securityscan = SecurityScanSerializer() class Meta(BaseObjectSerializer.Meta): model = VirtualServer - exclude = ('content_type', 'cluster') + exclude = ("content_type", "cluster") class VirtualServerSaveSerializer(RalphAPISaveSerializer): hypervisor = relations.PrimaryKeyRelatedField( - source='parent', queryset=DCHost.objects, + source="parent", + queryset=DCHost.objects, ) class Meta: model = VirtualServer - exclude = ('parent',) + exclude = ("parent",) class CloudFlavorViewSet(RalphAPIViewSet): queryset = CloudFlavor.objects.all() serializer_class = CloudFlavorSerializer save_serializer_class = SaveCloudFlavorSerializer - prefetch_related = ['tags', 'virtualcomponent_set__model'] - filter_fields = ['flavor_id'] + prefetch_related = ["tags", "virtualcomponent_set__model"] + filter_fields = ["flavor_id"] def destroy(self, request, *args, **kwargs): instance = self.get_object() - force_delete = request.data.get('force', False) + force_delete = request.data.get("force", False) if instance.cloudhost_set.count() != 0 and not force_delete: raise Conflict( _( "Cloud flavor is in use and hence is not deletable. " - "Use {\"force\": true} to force deletion." + 'Use {"force": true} to force deletion.' ) ) @@ -209,20 +208,20 @@ class CloudProviderViewSet(RalphAPIViewSet): def _require_force_delete(self, cloud_provider): return ( - cloud_provider.cloudflavor_set.count() != 0 or - cloud_provider.cloudhost_set.count() != 0 or - cloud_provider.cloudproject_set.count() != 0 + cloud_provider.cloudflavor_set.count() != 0 + or cloud_provider.cloudhost_set.count() != 0 + or cloud_provider.cloudproject_set.count() != 0 ) def destroy(self, request, *args, **kwargs): instance = self.get_object() - force_delete = request.data.get('force', False) + force_delete = request.data.get("force", False) if self._require_force_delete(instance) and not force_delete: raise Conflict( _( "Cloud provider is in use and hence is not deletable. " - "Use {\"force\": true} to force deletion." + 'Use {"force": true} to force deletion.' ) ) @@ -233,7 +232,7 @@ def destroy(self, request, *args, **kwargs): class CloudImageViewSet(RalphAPIViewSet): queryset = CloudImage.objects.all() serializer_class = CloudImageSerializer - filter_fields = ['image_id'] + filter_fields = ["image_id"] class CloudHostViewSet(BaseObjectViewSetMixin, RalphAPIViewSet): @@ -241,22 +240,26 @@ class CloudHostViewSet(BaseObjectViewSetMixin, RalphAPIViewSet): serializer_class = CloudHostSerializer save_serializer_class = SaveCloudHostSerializer select_related = [ - 'parent', 'parent__cloudproject', 'cloudprovider', 'hypervisor', - 'service_env__service', 'service_env__environment', 'content_type', - 'configuration_path__module', + "parent", + "parent__cloudproject", + "cloudprovider", + "hypervisor", + "service_env__service", + "service_env__environment", + "content_type", + "configuration_path__module", ] prefetch_related = base_object_descendant_prefetch_related + [ - 'tags', 'cloudflavor__virtualcomponent_set__model', 'licences', - Prefetch( - 'ethernet_set', - queryset=Ethernet.objects.select_related('ipaddress') - ), + "tags", + "cloudflavor__virtualcomponent_set__model", + "licences", + Prefetch("ethernet_set", queryset=Ethernet.objects.select_related("ipaddress")), ] filter_fields = [ - 'service_env__service__uid', - 'service_env__service__name', - 'service_env__service__id', + "service_env__service__uid", + "service_env__service__name", + "service_env__service__id", ] @@ -264,14 +267,17 @@ class CloudProjectViewSet(RalphAPIViewSet): queryset = CloudProject.objects.all() serializer_class = CloudProjectSerializer prefetch_related = [ - 'children', 'tags', 'licences', 'cloudprovider', + "children", + "tags", + "licences", + "cloudprovider", ] class VirtualServerTypeViewSet(RalphAPIViewSet): queryset = VirtualServerType.objects.all() serializer_class = VirtualServerTypeSerializer - filter_fields = ['name'] + filter_fields = ["name"] class VirtualServerFilterSet(NetworkableObjectFilters): @@ -285,38 +291,41 @@ class VirtualServerViewSet(BaseObjectViewSetMixin, RalphAPIViewSet): serializer_class = VirtualServerSerializer save_serializer_class = VirtualServerSaveSerializer select_related = VirtualServerAdmin.list_select_related + [ - 'parent', 'service_env__service', 'service_env__environment', - 'configuration_path', 'content_type', 'parent__cluster__type' + "parent", + "service_env__service", + "service_env__environment", + "configuration_path", + "content_type", + "parent__cluster__type", ] prefetch_related = base_object_descendant_prefetch_related + [ - 'tags', - 'memory_set', - 'processor_set', - 'disk_set', - Prefetch( - 'ethernet_set', - queryset=Ethernet.objects.select_related('ipaddress') - ), + "tags", + "memory_set", + "processor_set", + "disk_set", + Prefetch("ethernet_set", queryset=Ethernet.objects.select_related("ipaddress")), ] filter_fields = [ - 'service_env__service__uid', - 'service_env__service__name', - 'service_env__service__id', + "service_env__service__uid", + "service_env__service__name", + "service_env__service__id", ] additional_filter_class = VirtualServerFilterSet extended_filter_fields = dict( - list(BaseObjectViewSetMixin.extended_filter_fields.items()) + - list(dict( - hypervisor_service=['parent__service_env__service__uid'], - ).items()) + list(BaseObjectViewSetMixin.extended_filter_fields.items()) + + list( + dict( + hypervisor_service=["parent__service_env__service__uid"], + ).items() + ) ) -router.register(r'cloud-flavors', CloudFlavorViewSet) -router.register(r'cloud-hosts', CloudHostViewSet) -router.register(r'cloud-projects', CloudProjectViewSet) -router.register(r'cloud-providers', CloudProviderViewSet) -router.register(r'cloud-images', CloudImageViewSet) -router.register(r'virtual-servers', VirtualServerViewSet) -router.register(r'virtual-server-types', VirtualServerTypeViewSet) +router.register(r"cloud-flavors", CloudFlavorViewSet) +router.register(r"cloud-hosts", CloudHostViewSet) +router.register(r"cloud-projects", CloudProjectViewSet) +router.register(r"cloud-providers", CloudProviderViewSet) +router.register(r"cloud-images", CloudImageViewSet) +router.register(r"virtual-servers", VirtualServerViewSet) +router.register(r"virtual-server-types", VirtualServerTypeViewSet) urlpatterns = [] diff --git a/src/ralph/virtual/cloudsync.py b/src/ralph/virtual/cloudsync.py index c15d70ed7b..b3863df949 100644 --- a/src/ralph/virtual/cloudsync.py +++ b/src/ralph/virtual/cloudsync.py @@ -4,11 +4,7 @@ import pkg_resources from django.db.models import Q -from django.http import ( - HttpResponse, - HttpResponseBadRequest, - HttpResponseNotFound -) +from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST @@ -17,7 +13,7 @@ logger = logging.getLogger(__name__) -ENTRY_POINTS_GROUP = 'ralph.cloud_sync_processors' +ENTRY_POINTS_GROUP = "ralph.cloud_sync_processors" CLOUD_SYNC_DRIVERS = None LOCK = threading.Lock() @@ -34,7 +30,7 @@ def load_processors(): if CLOUD_SYNC_DRIVERS is not None: return - logger.info('Loading cloud sync processors.') + logger.info("Loading cloud sync processors.") CLOUD_SYNC_DRIVERS = {} @@ -43,8 +39,7 @@ def load_processors(): CLOUD_SYNC_DRIVERS[ep.name] = ep.resolve() except ImportError: logger.error( - 'Could not import DC asset event processor from %s.', - ep.module_name + "Could not import DC asset event processor from %s.", ep.module_name ) @@ -53,29 +48,28 @@ def load_processors(): def cloud_sync_router(request, cloud_provider_id): load_processors() - raw_data = request.read().decode('utf-8') + raw_data = request.read().decode("utf-8") try: event_data = json.loads(raw_data) except ValueError: - return HttpResponseBadRequest('Content must be a valid JSON text.') + return HttpResponseBadRequest("Content must be a valid JSON text.") try: cloud_provider = CloudProvider.objects.get( Q( pk=cloud_provider_id, cloud_sync_enabled=True, - cloud_sync_driver__isnull=False - ) & ~Q(cloud_sync_driver='') + cloud_sync_driver__isnull=False, + ) + & ~Q(cloud_sync_driver="") ) - processor = CLOUD_SYNC_DRIVERS[ - cloud_provider.cloud_sync_driver - ] + processor = CLOUD_SYNC_DRIVERS[cloud_provider.cloud_sync_driver] except CloudProvider.DoesNotExist: return HttpResponseNotFound() except KeyError: - return HttpResponse('Specified processor is not available', status=501) + return HttpResponse("Specified processor is not available", status=501) processor(cloud_provider, event_data) diff --git a/src/ralph/virtual/forms.py b/src/ralph/virtual/forms.py index 7b05048ae1..aca1111e69 100644 --- a/src/ralph/virtual/forms.py +++ b/src/ralph/virtual/forms.py @@ -10,20 +10,18 @@ class CloudProviderForm(RalphAdminFormMixin, forms.ModelForm): class Meta: model = CloudProvider - fields = ( - 'name', 'cloud_sync_enabled', 'cloud_sync_driver', 'client_config' - ) + fields = ("name", "cloud_sync_enabled", "cloud_sync_driver", "client_config") def clean_client_config(self): try: - client_config = self.cleaned_data.get('client_config') + client_config = self.cleaned_data.get("client_config") if client_config: json.loads(client_config) return client_config except json.JSONDecodeError as error: - self.add_error('client_config', error) + self.add_error("client_config", error) raise forms.ValidationError( - _('Client configuration must be a valid JSON text.') + _("Client configuration must be a valid JSON text.") ) diff --git a/src/ralph/virtual/management/commands/openstack_sync.py b/src/ralph/virtual/management/commands/openstack_sync.py index 20dfd27bf2..26985bf95b 100644 --- a/src/ralph/virtual/management/commands/openstack_sync.py +++ b/src/ralph/virtual/management/commands/openstack_sync.py @@ -14,14 +14,9 @@ from ralph.data_center.models.physical import DataCenterAsset from ralph.lib.openstack.client import ( RalphIronicClient, - RalphOpenStackInfrastructureClient -) -from ralph.virtual.models import ( - CloudFlavor, - CloudHost, - CloudProject, - CloudProvider + RalphOpenStackInfrastructureClient, ) +from ralph.virtual.models import CloudFlavor, CloudHost, CloudProject, CloudProvider logger = logging.getLogger(__name__) @@ -35,8 +30,11 @@ class SynchronizationType(Enum): class RalphClient: def __init__( - self, openstack_provider_name, ironic_serial_number_param, - ralph_serial_number_param, changes_since=None + self, + openstack_provider_name, + ironic_serial_number_param, + ralph_serial_number_param, + changes_since=None, ): self.cloud_provider = self._get_or_create_cloud_provider( openstack_provider_name @@ -44,12 +42,12 @@ def __init__( self.openstack_provider_name = openstack_provider_name self.ironic_serial_number_param = ironic_serial_number_param self.ralph_serial_number_param = ralph_serial_number_param - self.DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ' + self.DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" self.summary = defaultdict(int) if changes_since: - self.summary['sync_type'] = SynchronizationType.INCREMENTAL.name + self.summary["sync_type"] = SynchronizationType.INCREMENTAL.name else: - self.summary['sync_type'] = SynchronizationType.FULL.name + self.summary["sync_type"] = SynchronizationType.FULL.name def _get_or_create_cloud_provider(self, provider_name): """Get or create cloud provider object""" @@ -62,23 +60,23 @@ def _get_or_create_cloud_provider(self, provider_name): name=provider_name, ) self._save_object( - cloud_provider, 'Add {} CloudProvider'.format(provider_name) + cloud_provider, "Add {} CloudProvider".format(provider_name) ) return cloud_provider @classmethod def _get_project_info(cls, project): return { - 'name': project.name, - 'servers': {}, - 'tags': list(project.tags.names()), + "name": project.name, + "servers": {}, + "tags": list(project.tags.names()), } def get_ralph_projects(self): ralph_projects = {} projects = CloudProject.objects.filter( cloudprovider=self.cloud_provider - ).prefetch_related('tags') + ).prefetch_related("tags") for project in projects: project_id = project.project_id @@ -87,30 +85,34 @@ def get_ralph_projects(self): def get_ralph_flavors(self): ralph_flavors = {} - for flavor in CloudFlavor.objects.filter( - cloudprovider=self.cloud_provider - ): - ralph_flavors[flavor.flavor_id] = {'name': flavor.name} + for flavor in CloudFlavor.objects.filter(cloudprovider=self.cloud_provider): + ralph_flavors[flavor.flavor_id] = {"name": flavor.name} return ralph_flavors def get_ralph_servers_data(self, ralph_projects): """Get configuration from ralph DB""" - for server in CloudHost.objects.filter( - cloudprovider=self.cloud_provider, - ).select_related( - 'hypervisor', 'parent', 'parent__cloudproject', - ).prefetch_related('tags'): + for server in ( + CloudHost.objects.filter( + cloudprovider=self.cloud_provider, + ) + .select_related( + "hypervisor", + "parent", + "parent__cloudproject", + ) + .prefetch_related("tags") + ): ips = dict( - server.ethernet_set.select_related('ipaddress').values_list( - 'ipaddress__address', 'ipaddress__hostname' + server.ethernet_set.select_related("ipaddress").values_list( + "ipaddress__address", "ipaddress__hostname" ) ) new_server = { - 'hostname': server.hostname, - 'hypervisor': server.hypervisor, - 'tags': server.tags.names(), - 'ips': ips, - 'host_id': server.host_id, + "hostname": server.hostname, + "hypervisor": server.hypervisor, + "tags": server.tags.names(), + "ips": ips, + "host_id": server.host_id, } host_id = server.host_id project_id = server.parent.cloudproject.project_id @@ -119,7 +121,7 @@ def get_ralph_servers_data(self, ralph_projects): ralph_projects[project_id] = self._get_project_info( CloudProject.objects.get(project_id=project_id) ) - ralph_projects[project_id]['servers'][host_id] = new_server + ralph_projects[project_id]["servers"][host_id] = new_server return ralph_projects @staticmethod @@ -129,8 +131,7 @@ def _get_hypervisor(host_name, server_id): obj = DataCenterAsset.objects.get(hostname=host_name) return obj except (MultipleObjectsReturned, ObjectDoesNotExist): - logger.warning('Hypervisor %s not found for %s', - host_name, server_id) + logger.warning("Hypervisor %s not found for %s", host_name, server_id) return None def match_physical_and_cloud_hosts(self): @@ -138,8 +139,8 @@ def match_physical_and_cloud_hosts(self): for os_conf in settings.OPENSTACK_INSTANCES: if ( - os_conf.get('provider', DEFAULT_OPENSTACK_PROVIDER_NAME) != - self.openstack_provider_name + os_conf.get("provider", DEFAULT_OPENSTACK_PROVIDER_NAME) + != self.openstack_provider_name ): continue @@ -150,8 +151,8 @@ def _match_nodes_to_hosts(self, nodes): """Match iornic nodes to hosts.""" not_found_message_tpl = ( - '%s with the host id or serial number %s was not found. Check if ' - 'Ralph is synchronized with OpenStack or add it manually.' + "%s with the host id or serial number %s was not found. Check if " + "Ralph is synchronized with OpenStack or add it manually." ) for node in nodes: @@ -163,38 +164,27 @@ def _match_nodes_to_hosts(self, nodes): **{self.ralph_serial_number_param: node_sn} ) except DataCenterAsset.DoesNotExist: - logger.warning( - not_found_message_tpl, - 'DC asset', - node_sn - ) + logger.warning(not_found_message_tpl, "DC asset", node_sn) except CloudHost.DoesNotExist: - logger.warning( - not_found_message_tpl, - 'Cloud host', - node.instance_uuid - ) + logger.warning(not_found_message_tpl, "Cloud host", node.instance_uuid) except DataCenterAsset.MultipleObjectsReturned: logger.error( - 'Multiple DC assets were found for the serial number %s. ' - 'Please match Cloud host %s manually.', + "Multiple DC assets were found for the serial number %s. " + "Please match Cloud host %s manually.", node_sn, - host.id + host.id, ) except KeyError: logger.warning( - 'Could not get serial number of the Ironic node %s using ' - '%s extra parameter. Please check the configuration ' - 'of the node and submit a proper extra parameter or match ' - 'the node manually.', - node.uuid, self.ironic_serial_number_param + "Could not get serial number of the Ironic node %s using " + "%s extra parameter. Please check the configuration " + "of the node and submit a proper extra parameter or match " + "the node manually.", + node.uuid, + self.ironic_serial_number_param, ) else: - logger.info( - 'Cloud host %s matched DC asset %s.', - host.id, - asset.id - ) + logger.info("Cloud host %s matched DC asset %s.", host.id, asset.id) if host.hypervisor != asset: host.hypervisor = asset host.save() @@ -207,108 +197,104 @@ def _add_server(self, openstack_server, server_id, project_id): """add new server to ralph""" try: project = CloudProject.objects.get(project_id=project_id) - except ( - CloudProject.DoesNotExist, - CloudProject.MultipleObjectsReturned - ) as err: + except (CloudProject.DoesNotExist, CloudProject.MultipleObjectsReturned) as err: logger.warning( - 'Unable to assign project id of %s for host %s. Reason: %s', - project_id, openstack_server, err + "Unable to assign project id of %s for host %s. Reason: %s", + project_id, + openstack_server, + err, ) return try: - flavor = self._get_flavor_objects()[openstack_server['flavor_id']] + flavor = self._get_flavor_objects()[openstack_server["flavor_id"]] except KeyError: logger.warning( - 'Flavor %s not found for host %s', - openstack_server['flavor_id'], openstack_server + "Flavor %s not found for host %s", + openstack_server["flavor_id"], + openstack_server, ) return logger.info( - 'Creating new server %s (%s)', - server_id, openstack_server['hostname'] + "Creating new server %s (%s)", server_id, openstack_server["hostname"] ) new_server = CloudHost( - hostname=openstack_server['hostname'], + hostname=openstack_server["hostname"], cloudflavor=flavor, parent=project, host_id=server_id, - hypervisor=self._get_hypervisor( - openstack_server['hypervisor'], server_id - ), + hypervisor=self._get_hypervisor(openstack_server["hypervisor"], server_id), cloudprovider=self.cloud_provider, - image_name=openstack_server['image'], + image_name=openstack_server["image"], ) # workaround - created field has auto_now_add attribute new_server.save() - new_server.created = datetime.strptime(openstack_server['created'], - self.DATETIME_FORMAT) - self._save_object(new_server, 'add server %s' - % new_server.hostname) + new_server.created = datetime.strptime( + openstack_server["created"], self.DATETIME_FORMAT + ) + self._save_object(new_server, "add server %s" % new_server.hostname) - new_server.tags.add(openstack_server['tag']) + new_server.tags.add(openstack_server["tag"]) with transaction.atomic(), revisions.create_revision(): - new_server.ip_addresses = openstack_server['ips'] - revisions.set_comment('Assign ip addresses to a host') + new_server.ip_addresses = openstack_server["ips"] + revisions.set_comment("Assign ip addresses to a host") def _update_server(self, openstack_server, server_id, ralph_server): """Compare and apply changes to a CloudHost""" modified = False obj = CloudHost.objects.get(host_id=server_id) try: - flavor = self._get_flavor_objects()[openstack_server['flavor_id']] + flavor = self._get_flavor_objects()[openstack_server["flavor_id"]] except KeyError: logger.warning( - 'Flavor %s not found for host %s', - openstack_server['flavor_id'], openstack_server + "Flavor %s not found for host %s", + openstack_server["flavor_id"], + openstack_server, ) return - if obj.hostname != openstack_server['hostname']: - logger.info('Updating hostname ({}) for {}'.format( - openstack_server['hostname'], server_id - )) - obj.hostname = openstack_server['hostname'] - self._save_object(obj, 'Modify hostname') + if obj.hostname != openstack_server["hostname"]: + logger.info( + "Updating hostname ({}) for {}".format( + openstack_server["hostname"], server_id + ) + ) + obj.hostname = openstack_server["hostname"] + self._save_object(obj, "Modify hostname") modified = True if obj.cloudflavor != flavor: - logger.info('Updating flavor ({}) for {}'.format( - flavor, server_id - )) + logger.info("Updating flavor ({}) for {}".format(flavor, server_id)) obj.cloudflavor = flavor - self._save_object(obj, 'Modify cloudflavor') + self._save_object(obj, "Modify cloudflavor") modified = True - hypervisor = self._get_hypervisor( - openstack_server['hypervisor'], server_id - ) + hypervisor = self._get_hypervisor(openstack_server["hypervisor"], server_id) if obj.hypervisor != hypervisor: - logger.info('Updating hypervisor ({}) for {}'.format( - hypervisor, server_id - )) + logger.info("Updating hypervisor ({}) for {}".format(hypervisor, server_id)) obj.hypervisor = hypervisor - self._save_object(obj, 'Modify hypervisor') + self._save_object(obj, "Modify hypervisor") modified = True - if obj.image_name != openstack_server['image']: - logger.info('Updating image ({}) for {}'.format( - openstack_server['image'], server_id - )) - obj.image_name = openstack_server['image'] - self._save_object(obj, 'Updated image info') + if obj.image_name != openstack_server["image"]: + logger.info( + "Updating image ({}) for {}".format( + openstack_server["image"], server_id + ) + ) + obj.image_name = openstack_server["image"] + self._save_object(obj, "Updated image info") modified = True - if openstack_server['tag'] not in ralph_server['tags']: - obj.tags.add(openstack_server['tag']) + if openstack_server["tag"] not in ralph_server["tags"]: + obj.tags.add(openstack_server["tag"]) # add/remove IPs - if openstack_server['ips'] != ralph_server['ips']: + if openstack_server["ips"] != ralph_server["ips"]: modified = True with transaction.atomic(), revisions.create_revision(): - obj.ip_addresses = openstack_server['ips'] - revisions.set_comment('Assign ip addresses to a host') + obj.ip_addresses = openstack_server["ips"] + revisions.set_comment("Assign ip addresses to a host") return modified @@ -321,15 +307,15 @@ def _add_or_update_servers( # included in data received from Openstack. This method only # updates servers or creates new ones. There is a separate method # for server deletion (`_delete_servers`). - if server['status'] == 'DELETED': + if server["status"] == "DELETED": continue try: ralph_server = ( - ralph_projects[openstack_project_id]['servers'][server_id] # noqa + ralph_projects[openstack_project_id]["servers"][server_id] # noqa ) except KeyError: self._add_server(server, server_id, openstack_project_id) - self.summary['new_instances'] += 1 + self.summary["new_instances"] += 1 else: modified = self._update_server( server, @@ -337,26 +323,22 @@ def _add_or_update_servers( ralph_server, ) if modified: - self.summary['mod_instances'] += 1 - self.summary['total_instances'] += 1 + self.summary["mod_instances"] += 1 + self.summary["total_instances"] += 1 def _calculate_servers_to_delete( self, openstack_project_servers, openstack_project_id, ralph_projects ): project = ralph_projects.get(openstack_project_id, None) if project: - return list( - project['servers'].keys() - - openstack_project_servers.keys() - ) + return list(project["servers"].keys() - openstack_project_servers.keys()) return [] - def _calculate_servers_to_delete_incremental( - self, openstack_project_servers - ): + def _calculate_servers_to_delete_incremental(self, openstack_project_servers): return [ - server for server, data in openstack_project_servers.items() - if data.get('status') == 'DELETED' + server + for server, data in openstack_project_servers.items() + if data.get("status") == "DELETED" ] def _delete_servers(self, servers): @@ -364,12 +346,9 @@ def _delete_servers(self, servers): try: for server_id in servers: host = CloudHost.objects.get(host_id=server_id) - logger.warning( - 'Removing CloudHost %s (%s)', - server_id, host.hostname - ) + logger.warning("Removing CloudHost %s (%s)", server_id, host.hostname) self._delete_object(host) - self.summary['del_instances'] += 1 + self.summary["del_instances"] += 1 except (KeyError, ObjectDoesNotExist): pass @@ -381,87 +360,80 @@ def _add_or_update_projects( project = CloudProject.objects.get(project_id=openstack_project_id) ralph_project = ralph_projects[openstack_project_id] modified = False - if ralph_project['name'] != openstack_project_data['name']: + if ralph_project["name"] != openstack_project_data["name"]: modified = True - project.name = openstack_project_data['name'] - self._save_object(project, 'Modify name') + project.name = openstack_project_data["name"] + self._save_object(project, "Modify name") if not all( - [ - tag in ralph_project['tags'] - for tag in openstack_project_data['tags'] - ] + [tag in ralph_project["tags"] for tag in openstack_project_data["tags"]] ): modified = True - for tag in openstack_project_data['tags']: + for tag in openstack_project_data["tags"]: project.tags.add(tag) if modified: - self.summary['mod_projects'] += 1 + self.summary["mod_projects"] += 1 else: - self.summary['new_projects'] += 1 + self.summary["new_projects"] += 1 project = CloudProject( - name=openstack_project_data['name'], + name=openstack_project_data["name"], project_id=openstack_project_id, cloudprovider=self.cloud_provider, ) try: with transaction.atomic(): - self._save_object(project, 'Add project %s' % project.name) + self._save_object(project, "Add project %s" % project.name) except IntegrityError: logger.warning( - 'Duplicated project ID (%s) for project %s', - project.project_id, project.name + "Duplicated project ID (%s) for project %s", + project.project_id, + project.name, ) - project = CloudProject.objects.get( - project_id=openstack_project_id - ) - for tag in openstack_project_data['tags']: + project = CloudProject.objects.get(project_id=openstack_project_id) + for tag in openstack_project_data["tags"]: project.tags.add(tag) - self.summary['total_projects'] += 1 + self.summary["total_projects"] += 1 def _add_or_modify_flavours(self, flavor, flavor_id, ralph_flavors): """Add/modify flavor in ralph""" if flavor_id not in ralph_flavors: new_flavor = CloudFlavor( - name=flavor['name'], + name=flavor["name"], flavor_id=flavor_id, - cloudprovider=self.cloud_provider + cloudprovider=self.cloud_provider, ) - self._save_object(new_flavor, 'Add new flavor') - new_flavor.tags.add(flavor['tag']) - for component in ['cores', 'memory', 'disk']: + self._save_object(new_flavor, "Add new flavor") + new_flavor.tags.add(flavor["tag"]) + for component in ["cores", "memory", "disk"]: setattr(new_flavor, component, flavor[component]) - self.summary['new_flavors'] += 1 + self.summary["new_flavors"] += 1 else: mod = False obj = CloudFlavor.objects.get(flavor_id=flavor_id) - if ralph_flavors[flavor_id]['name'] != flavor['name']: - obj.name = flavor['name'] - self._save_object(obj, 'Change name') + if ralph_flavors[flavor_id]["name"] != flavor["name"]: + obj.name = flavor["name"] + self._save_object(obj, "Change name") mod = True - if flavor['tag'] not in obj.tags.names(): - obj.tags.add(flavor['tag']) + if flavor["tag"] not in obj.tags.names(): + obj.tags.add(flavor["tag"]) mod = True - for component in ['cores', 'memory', 'disk']: + for component in ["cores", "memory", "disk"]: if flavor[component] != getattr(obj, component): with transaction.atomic(), revisions.create_revision(): - revisions.set_comment( - 'Change {} value'.format(component) - ) + revisions.set_comment("Change {} value".format(component)) setattr(obj, component, flavor[component]) mod = True if mod: - self.summary['mod_flavors'] += 1 - self.summary['total_flavors'] += 1 + self.summary["mod_flavors"] += 1 + self.summary["total_flavors"] += 1 def perform_update( - self, openstack_projects, openstack_flavors, ralph_projects, - ralph_flavors + self, openstack_projects, openstack_flavors, ralph_projects, ralph_flavors ): """Update existing and add new ralph data""" - logger.info('Updating Ralph entries') + logger.info("Updating Ralph entries") for flavor_id in openstack_flavors: self._add_or_modify_flavours( openstack_flavors[flavor_id], flavor_id, ralph_flavors @@ -472,8 +444,7 @@ def perform_update( openstack_projects[project_id], project_id, ralph_projects ) self._add_or_update_servers( - openstack_projects[project_id]['servers'], - project_id, ralph_projects + openstack_projects[project_id]["servers"], project_id, ralph_projects ) def calculate_servers_to_delete( @@ -484,21 +455,26 @@ def calculate_servers_to_delete( if incremental: servers_to_delete.extend( self._calculate_servers_to_delete_incremental( - openstack_projects[project_id]['servers'] + openstack_projects[project_id]["servers"] ) ) else: servers_to_delete.extend( self._calculate_servers_to_delete( - openstack_projects[project_id]['servers'], project_id, - ralph_projects + openstack_projects[project_id]["servers"], + project_id, + ralph_projects, ) ) return servers_to_delete def perform_delete( - self, openstack_projects, openstack_flavors, ralph_projects, - ralph_flavors, servers_to_delete + self, + openstack_projects, + openstack_flavors, + ralph_projects, + ralph_flavors, + servers_to_delete, ): """ Remove servers that don't exist in openstack from ralph (servers to @@ -507,66 +483,61 @@ def perform_delete( ralph. """ self._delete_servers(servers_to_delete) - for project_id in (set(ralph_projects.keys()) - set( - openstack_projects.keys()) - ): + for project_id in set(ralph_projects.keys()) - set(openstack_projects.keys()): cloud_project = CloudProject.objects.get( - project_id=project_id, - cloudprovider=self.cloud_provider + project_id=project_id, cloudprovider=self.cloud_provider ) if not cloud_project: continue children_count = cloud_project.children.count() logger_extras = { - 'cloud_project_name': cloud_project.name, - 'cloud_project_id': cloud_project.id + "cloud_project_name": cloud_project.name, + "cloud_project_id": cloud_project.id, } if children_count == 0: self._delete_object(cloud_project) logger.debug( - 'Deleted Cloud Project (name: {}, id: {})'.format( + "Deleted Cloud Project (name: {}, id: {})".format( cloud_project.name, cloud_project.id, ), - extra=logger_extras + extra=logger_extras, ) - self.summary['del_projects'] += 1 + self.summary["del_projects"] += 1 else: logger.error( - 'Cloud project name: %s id: %s cant\'t be deleted ' - 'because it has %s children', + "Cloud project name: %s id: %s cant't be deleted " + "because it has %s children", cloud_project.name, cloud_project.id, children_count, - extra=logger_extras + extra=logger_extras, ) - for del_flavor in (set(ralph_flavors) - set(openstack_flavors)): + for del_flavor in set(ralph_flavors) - set(openstack_flavors): flavor = CloudFlavor.objects.get(flavor_id=del_flavor) assignment_count = flavor.cloudhost_set.count() if assignment_count: logger_extras = { - 'cloud_flavor_name': flavor.name, - 'cloud_flavor_id': flavor.flavor_id + "cloud_flavor_name": flavor.name, + "cloud_flavor_id": flavor.flavor_id, } logger.error( - 'Cloud flavor name: %s id: %s cant\'t be deleted ' - 'because it is assigned to %s cloud hosts.', + "Cloud flavor name: %s id: %s cant't be deleted " + "because it is assigned to %s cloud hosts.", flavor.name, flavor.flavor_id, assignment_count, - extra=logger_extras + extra=logger_extras, ) else: - self._delete_object(CloudFlavor.objects.get( - flavor_id=del_flavor) - ) - self.summary['del_flavors'] += 1 + self._delete_object(CloudFlavor.objects.get(flavor_id=del_flavor)) + self.summary["del_flavors"] += 1 @staticmethod def _save_object(obj, comment): """Save an object and create revision""" - logger.info('Saving {} (id: {}; {})'.format(obj, obj.id, comment)) + logger.info("Saving {} (id: {}; {})".format(obj, obj.id, comment)) with transaction.atomic(), revisions.create_revision(): obj.save() revisions.set_comment(comment) @@ -574,10 +545,10 @@ def _save_object(obj, comment): @staticmethod def _delete_object(obj): """Save an object and delete revision""" - logger.warning('Deleting %s (id: %s)', obj, obj.id) + logger.warning("Deleting %s (id: %s)", obj, obj.id) with transaction.atomic(), revisions.create_revision(): obj.delete() - revisions.set_comment('openstack_sync::_delete_object') + revisions.set_comment("openstack_sync::_delete_object") def print_summary(self, stdout): """ @@ -605,9 +576,7 @@ def print_summary(self, stdout): Modified flavors: {summary[mod_flavors]} Deleted flavors: {summary[del_flavors]} Total flavors: {summary[total_flavors]} - """.format( - summary=self.summary - ) + """.format(summary=self.summary) stdout.write(msg) logger.info(msg) @@ -617,73 +586,68 @@ class Command(BaseCommand): def add_arguments(self, parser): super().add_arguments(parser) parser.add_argument( - '--provider', - help='OpenStack provider name', + "--provider", + help="OpenStack provider name", default=DEFAULT_OPENSTACK_PROVIDER_NAME, ) parser.add_argument( - '--match-ironic-physical-hosts', - action='store_true', - help='Match physical hosts and baremetal instances' + "--match-ironic-physical-hosts", + action="store_true", + help="Match physical hosts and baremetal instances", ) parser.add_argument( - '--node-serial-number-parameter', + "--node-serial-number-parameter", type=str, - default='serial_number', - help="Extra parameter used to store node serial numbers in Ironic" + default="serial_number", + help="Extra parameter used to store node serial numbers in Ironic", ) parser.add_argument( - '--asset-serial-number-parameter', + "--asset-serial-number-parameter", type=str, - default='sn', - help="Parameter used to store asset serial numbers in Ralph" + default="sn", + help="Parameter used to store asset serial numbers in Ralph", ) parser.add_argument( - '--changes-since', + "--changes-since", type=int, default=0, help="Synchronize only most recent changes. Specify number of " - "minutes to go back in time. 0 means synchronize everything." + "minutes to go back in time. 0 means synchronize everything.", ) def handle(self, *args, **options): try: - if not hasattr(settings, 'OPENSTACK_INSTANCES'): - logger.error('Nothing to sync') + if not hasattr(settings, "OPENSTACK_INSTANCES"): + logger.error("Nothing to sync") return - logger.info('Openstack sync started...') - match_ironic = options['match_ironic_physical_hosts'] - openstack_provider_name = options['provider'] - ironic_serial_number_param = options[ - 'node_serial_number_parameter' - ] - ralph_serial_number_param = options[ - 'asset_serial_number_parameter' - ] - changes_since = options['changes_since'] + logger.info("Openstack sync started...") + match_ironic = options["match_ironic_physical_hosts"] + openstack_provider_name = options["provider"] + ironic_serial_number_param = options["node_serial_number_parameter"] + ralph_serial_number_param = options["asset_serial_number_parameter"] + changes_since = options["changes_since"] openstack_search_options = None if changes_since: openstack_search_options = { - 'changes-since': - datetime.now() - timedelta(minutes=changes_since) + "changes-since": datetime.now() - timedelta(minutes=changes_since) } # Fetch data from Openstack - openstack = RalphOpenStackInfrastructureClient( - openstack_provider_name - ) + openstack = RalphOpenStackInfrastructureClient(openstack_provider_name) openstack_flavors = openstack.get_openstack_flavors() openstack_projects = openstack.get_openstack_projects() - openstack_projects, openstack_flavors = \ + openstack_projects, openstack_flavors = ( openstack.get_openstack_instances_data( - openstack_projects, openstack_flavors, - openstack_search_options + openstack_projects, openstack_flavors, openstack_search_options ) + ) # Fetch data from Ralph ralph = RalphClient( - openstack_provider_name, ironic_serial_number_param, - ralph_serial_number_param, changes_since + openstack_provider_name, + ironic_serial_number_param, + ralph_serial_number_param, + changes_since, ) ralph_projects = ralph.get_ralph_projects() ralph_flavors = ralph.get_ralph_flavors() @@ -691,25 +655,24 @@ def handle(self, *args, **options): # Add and update data in Ralph ralph.perform_update( - openstack_projects, openstack_flavors, ralph_projects, - ralph_flavors + openstack_projects, openstack_flavors, ralph_projects, ralph_flavors ) if match_ironic: ralph.match_physical_and_cloud_hosts() # Delete data in Ralph servers_to_delete = ralph.calculate_servers_to_delete( - openstack_projects, ralph_projects, - incremental=bool(changes_since) + openstack_projects, ralph_projects, incremental=bool(changes_since) ) ralph.perform_delete( - openstack_projects, openstack_flavors, ralph_projects, - ralph_flavors, servers_to_delete + openstack_projects, + openstack_flavors, + ralph_projects, + ralph_flavors, + servers_to_delete, ) # Print summary ralph.print_summary(self.stdout) except Exception as err: - logger.exception( - 'Openstack sync failed with error: {}'.format(err) - ) + logger.exception("Openstack sync failed with error: {}".format(err)) diff --git a/src/ralph/virtual/migrations/0001_initial.py b/src/ralph/virtual/migrations/0001_initial.py index 99c345a121..4dd59c05a8 100644 --- a/src/ralph/virtual/migrations/0001_initial.py +++ b/src/ralph/virtual/migrations/0001_initial.py @@ -6,35 +6,54 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0008_auto_20160122_1429'), - ('data_center', '0007_auto_20160225_1818'), + ("assets", "0008_auto_20160122_1429"), + ("data_center", "0007_auto_20160225_1818"), ] # move models from data_center app state_operations = [ migrations.CreateModel( - name='CloudProject', + name="CloudProject", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.CreateModel( - name='VirtualServer', + name="VirtualServer", fields=[ - ('baseobject_ptr', models.OneToOneField(primary_key=True, to='assets.BaseObject', auto_created=True, parent_link=True, serialize=False, on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + primary_key=True, + to="assets.BaseObject", + auto_created=True, + parent_link=True, + serialize=False, + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name': 'Virtual server (VM)', - 'verbose_name_plural': 'Virtual servers (VM)', - 'abstract': False, + "verbose_name": "Virtual server (VM)", + "verbose_name_plural": "Virtual servers (VM)", + "abstract": False, }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), ] diff --git a/src/ralph/virtual/migrations/0002_auto_20160226_0826.py b/src/ralph/virtual/migrations/0002_auto_20160226_0826.py index 507c109912..ce4f0f3e31 100644 --- a/src/ralph/virtual/migrations/0002_auto_20160226_0826.py +++ b/src/ralph/virtual/migrations/0002_auto_20160226_0826.py @@ -6,94 +6,169 @@ class Migration(migrations.Migration): - dependencies = [ - ('assets', '0008_auto_20160122_1429'), - ('data_center', '0007_auto_20160225_1818'), - ('virtual', '0001_initial'), + ("assets", "0008_auto_20160122_1429"), + ("data_center", "0007_auto_20160225_1818"), + ("virtual", "0001_initial"), ] operations = [ migrations.CreateModel( - name='CloudFlavor', + name="CloudFlavor", fields=[ - ('baseobject_ptr', models.OneToOneField(serialize=False, auto_created=True, primary_key=True, parent_link=True, to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('name', models.CharField(max_length=255, verbose_name='name')), - ('flavor_id', models.CharField(unique=True, max_length=100)), + ( + "baseobject_ptr", + models.OneToOneField( + serialize=False, + auto_created=True, + primary_key=True, + parent_link=True, + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("name", models.CharField(max_length=255, verbose_name="name")), + ("flavor_id", models.CharField(unique=True, max_length=100)), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.CreateModel( - name='CloudHost', + name="CloudHost", fields=[ - ('baseobject_ptr', models.OneToOneField(serialize=False, auto_created=True, primary_key=True, parent_link=True, to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE)), - ('host_id', models.CharField(unique=True, max_length=100)), - ('hostname', models.CharField(max_length=100)), - ('image_name', models.CharField(blank=True, null=True, max_length=255)), - ('cloudflavor', models.ForeignKey(verbose_name='Instance Type', to='virtual.CloudFlavor', on_delete=django.db.models.deletion.CASCADE)), + ( + "baseobject_ptr", + models.OneToOneField( + serialize=False, + auto_created=True, + primary_key=True, + parent_link=True, + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ("host_id", models.CharField(unique=True, max_length=100)), + ("hostname", models.CharField(max_length=100)), + ("image_name", models.CharField(blank=True, null=True, max_length=255)), + ( + "cloudflavor", + models.ForeignKey( + verbose_name="Instance Type", + to="virtual.CloudFlavor", + on_delete=django.db.models.deletion.CASCADE, + ), + ), ], options={ - 'verbose_name_plural': 'Cloud hosts', - 'verbose_name': 'Cloud host', + "verbose_name_plural": "Cloud hosts", + "verbose_name": "Cloud host", }, - bases=('assets.baseobject',), + bases=("assets.baseobject",), ), migrations.CreateModel( - name='CloudProvider', + name="CloudProvider", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(unique=True, max_length=255, verbose_name='name')), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "name", + models.CharField(unique=True, max_length=255, verbose_name="name"), + ), ], options={ - 'verbose_name_plural': 'Cloud providers', - 'verbose_name': 'Cloud provider', + "verbose_name_plural": "Cloud providers", + "verbose_name": "Cloud provider", }, ), migrations.CreateModel( - name='VirtualComponent', + name="VirtualComponent", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('base_object', models.ForeignKey(to='assets.BaseObject', related_name='virtualcomponent', on_delete=django.db.models.deletion.CASCADE)), - ('model', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, verbose_name='model', to='assets.ComponentModel')), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ( + "base_object", + models.ForeignKey( + to="assets.BaseObject", + related_name="virtualcomponent", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + ( + "model", + models.ForeignKey( + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + verbose_name="model", + to="assets.ComponentModel", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.AddField( - model_name='cloudproject', - name='name', - field=models.CharField(default='', max_length=100), + model_name="cloudproject", + name="name", + field=models.CharField(default="", max_length=100), preserve_default=False, ), migrations.AddField( - model_name='cloudproject', - name='project_id', + model_name="cloudproject", + name="project_id", field=models.CharField(default=1, unique=True, max_length=100), preserve_default=False, ), migrations.AddField( - model_name='cloudhost', - name='cloudprovider', - field=models.ForeignKey(to='virtual.CloudProvider', on_delete=django.db.models.deletion.CASCADE), + model_name="cloudhost", + name="cloudprovider", + field=models.ForeignKey( + to="virtual.CloudProvider", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AddField( - model_name='cloudhost', - name='hypervisor', - field=models.ForeignKey(blank=True, null=True, to='data_center.DataCenterAsset', on_delete=django.db.models.deletion.CASCADE), + model_name="cloudhost", + name="hypervisor", + field=models.ForeignKey( + blank=True, + null=True, + to="data_center.DataCenterAsset", + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='cloudflavor', - name='cloudprovider', - field=models.ForeignKey(to='virtual.CloudProvider', on_delete=django.db.models.deletion.CASCADE), + model_name="cloudflavor", + name="cloudprovider", + field=models.ForeignKey( + to="virtual.CloudProvider", on_delete=django.db.models.deletion.CASCADE + ), ), migrations.AddField( - model_name='cloudproject', - name='cloudprovider', - field=models.ForeignKey(default=1, to='virtual.CloudProvider', on_delete=django.db.models.deletion.CASCADE), + model_name="cloudproject", + name="cloudprovider", + field=models.ForeignKey( + default=1, + to="virtual.CloudProvider", + on_delete=django.db.models.deletion.CASCADE, + ), preserve_default=False, ), ] diff --git a/src/ralph/virtual/migrations/0003_auto_20160606_1442.py b/src/ralph/virtual/migrations/0003_auto_20160606_1442.py index eec868281c..c08d3c43ca 100644 --- a/src/ralph/virtual/migrations/0003_auto_20160606_1442.py +++ b/src/ralph/virtual/migrations/0003_auto_20160606_1442.py @@ -8,58 +8,100 @@ class Migration(migrations.Migration): - dependencies = [ - ('data_center', '0013_auto_20160606_1438'), - ('virtual', '0002_auto_20160226_0826'), + ("data_center", "0013_auto_20160606_1438"), + ("virtual", "0002_auto_20160226_0826"), ] operations = [ migrations.CreateModel( - name='VirtualServerType', + name="VirtualServerType", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('name', models.CharField(max_length=75, verbose_name='name')), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), - ('modified', models.DateTimeField(auto_now=True, verbose_name='last modified')), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=75, verbose_name="name")), + ( + "created", + models.DateTimeField( + auto_now_add=True, verbose_name="date created" + ), + ), + ( + "modified", + models.DateTimeField(auto_now=True, verbose_name="last modified"), + ), ], options={ - 'ordering': ['name'], - 'abstract': False, + "ordering": ["name"], + "abstract": False, }, ), migrations.AddField( - model_name='virtualcomponent', - name='created', - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2016, 6, 6, 14, 41, 55, 331734), verbose_name='date created'), + model_name="virtualcomponent", + name="created", + field=models.DateTimeField( + auto_now_add=True, + default=datetime.datetime(2016, 6, 6, 14, 41, 55, 331734), + verbose_name="date created", + ), preserve_default=False, ), migrations.AddField( - model_name='virtualcomponent', - name='modified', - field=models.DateTimeField(auto_now=True, default=datetime.datetime(2016, 6, 6, 14, 41, 58, 683625), verbose_name='last modified'), + model_name="virtualcomponent", + name="modified", + field=models.DateTimeField( + auto_now=True, + default=datetime.datetime(2016, 6, 6, 14, 41, 58, 683625), + verbose_name="last modified", + ), preserve_default=False, ), migrations.AddField( - model_name='virtualserver', - name='cluster', - field=models.ForeignKey(blank=True, to='data_center.Cluster', null=True, on_delete=django.db.models.deletion.CASCADE), + model_name="virtualserver", + name="cluster", + field=models.ForeignKey( + blank=True, + to="data_center.Cluster", + null=True, + on_delete=django.db.models.deletion.CASCADE, + ), ), migrations.AddField( - model_name='virtualserver', - name='hostname', - field=ralph.lib.mixins.fields.NullableCharField(null=True, default=None, blank=True, max_length=255, verbose_name='hostname', unique=True), + model_name="virtualserver", + name="hostname", + field=ralph.lib.mixins.fields.NullableCharField( + null=True, + default=None, + blank=True, + max_length=255, + verbose_name="hostname", + unique=True, + ), ), migrations.AddField( - model_name='virtualserver', - name='sn', - field=models.CharField(max_length=200, default=1, verbose_name='SN', unique=True), + model_name="virtualserver", + name="sn", + field=models.CharField( + max_length=200, default=1, verbose_name="SN", unique=True + ), preserve_default=False, ), migrations.AddField( - model_name='virtualserver', - name='type', - field=models.ForeignKey(default=1, to='virtual.VirtualServerType', related_name='virtual_servers', on_delete=django.db.models.deletion.CASCADE), + model_name="virtualserver", + name="type", + field=models.ForeignKey( + default=1, + to="virtual.VirtualServerType", + related_name="virtual_servers", + on_delete=django.db.models.deletion.CASCADE, + ), preserve_default=False, ), ] diff --git a/src/ralph/virtual/migrations/0004_virtualserver_status.py b/src/ralph/virtual/migrations/0004_virtualserver_status.py index 98d05461a2..0308d566b4 100644 --- a/src/ralph/virtual/migrations/0004_virtualserver_status.py +++ b/src/ralph/virtual/migrations/0004_virtualserver_status.py @@ -1,20 +1,27 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import ralph.lib.transitions.fields class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0003_auto_20160606_1442'), + ("virtual", "0003_auto_20160606_1442"), ] operations = [ migrations.AddField( - model_name='virtualserver', - name='status', - field=ralph.lib.transitions.fields.TransitionField(default=1, choices=[(1, 'new'), (2, 'in use'), (3, 'to deploy'), (4, 'liquidated')]), + model_name="virtualserver", + name="status", + field=ralph.lib.transitions.fields.TransitionField( + default=1, + choices=[ + (1, "new"), + (2, "in use"), + (3, "to deploy"), + (4, "liquidated"), + ], + ), ), ] diff --git a/src/ralph/virtual/migrations/0005_auto_20160615_2140.py b/src/ralph/virtual/migrations/0005_auto_20160615_2140.py index 40599da0f4..be1f09d3f2 100644 --- a/src/ralph/virtual/migrations/0005_auto_20160615_2140.py +++ b/src/ralph/virtual/migrations/0005_auto_20160615_2140.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0004_virtualserver_status'), + ("virtual", "0004_virtualserver_status"), ] operations = [ migrations.AlterField( - model_name='virtualcomponent', - name='base_object', - field=models.ForeignKey(related_name='virtualcomponent_set', to='assets.BaseObject', on_delete=django.db.models.deletion.CASCADE), + model_name="virtualcomponent", + name="base_object", + field=models.ForeignKey( + related_name="virtualcomponent_set", + to="assets.BaseObject", + on_delete=django.db.models.deletion.CASCADE, + ), ), ] diff --git a/src/ralph/virtual/migrations/0006_virtualcomponent_model_name.py b/src/ralph/virtual/migrations/0006_virtualcomponent_model_name.py index 44886ba9cf..7c269cf9c2 100644 --- a/src/ralph/virtual/migrations/0006_virtualcomponent_model_name.py +++ b/src/ralph/virtual/migrations/0006_virtualcomponent_model_name.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0005_auto_20160615_2140'), + ("virtual", "0005_auto_20160615_2140"), ] operations = [ migrations.AddField( - model_name='virtualcomponent', - name='model_name', - field=models.CharField(max_length=255, verbose_name='model name', blank=True, null=True), + model_name="virtualcomponent", + name="model_name", + field=models.CharField( + max_length=255, verbose_name="model name", blank=True, null=True + ), ), ] diff --git a/src/ralph/virtual/migrations/0007_auto_20160630_0949.py b/src/ralph/virtual/migrations/0007_auto_20160630_0949.py index 1abcfc8fe3..507118474c 100644 --- a/src/ralph/virtual/migrations/0007_auto_20160630_0949.py +++ b/src/ralph/virtual/migrations/0007_auto_20160630_0949.py @@ -6,20 +6,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0006_virtualcomponent_model_name'), + ("virtual", "0006_virtualcomponent_model_name"), ] operations = [ migrations.AlterField( - model_name='virtualserver', - name='sn', - field=ralph.lib.mixins.fields.NullableCharField(max_length=200, null=True, blank=True, verbose_name='SN', default=None, unique=True), + model_name="virtualserver", + name="sn", + field=ralph.lib.mixins.fields.NullableCharField( + max_length=200, + null=True, + blank=True, + verbose_name="SN", + default=None, + unique=True, + ), ), migrations.AlterField( - model_name='virtualservertype', - name='name', - field=models.CharField(verbose_name='name', max_length=255, unique=True), + model_name="virtualservertype", + name="name", + field=models.CharField(verbose_name="name", max_length=255, unique=True), ), ] diff --git a/src/ralph/virtual/migrations/0008_auto_20160823_0921.py b/src/ralph/virtual/migrations/0008_auto_20160823_0921.py index f954d74bd2..cc66f1d63b 100644 --- a/src/ralph/virtual/migrations/0008_auto_20160823_0921.py +++ b/src/ralph/virtual/migrations/0008_auto_20160823_0921.py @@ -5,25 +5,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0007_auto_20160630_0949'), + ("virtual", "0007_auto_20160630_0949"), ] operations = [ migrations.AlterField( - model_name='cloudhost', - name='host_id', - field=models.CharField(unique=True, max_length=100, verbose_name='host ID'), + model_name="cloudhost", + name="host_id", + field=models.CharField(unique=True, max_length=100, verbose_name="host ID"), ), migrations.AlterField( - model_name='cloudhost', - name='hostname', - field=models.CharField(max_length=100, verbose_name='hostname'), + model_name="cloudhost", + name="hostname", + field=models.CharField(max_length=100, verbose_name="hostname"), ), migrations.AlterField( - model_name='cloudproject', - name='project_id', - field=models.CharField(unique=True, max_length=100, verbose_name='project ID'), + model_name="cloudproject", + name="project_id", + field=models.CharField( + unique=True, max_length=100, verbose_name="project ID" + ), ), ] diff --git a/src/ralph/virtual/migrations/0009_auto_20170522_0745.py b/src/ralph/virtual/migrations/0009_auto_20170522_0745.py index edb10c5068..eb77083dc6 100644 --- a/src/ralph/virtual/migrations/0009_auto_20170522_0745.py +++ b/src/ralph/virtual/migrations/0009_auto_20170522_0745.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0008_auto_20160823_0921'), + ("virtual", "0008_auto_20160823_0921"), ] operations = [ migrations.AlterField( - model_name='cloudhost', - name='hostname', - field=models.CharField(verbose_name='hostname', max_length=255), + model_name="cloudhost", + name="hostname", + field=models.CharField(verbose_name="hostname", max_length=255), ), ] diff --git a/src/ralph/virtual/migrations/0010_auto_20181018_0822.py b/src/ralph/virtual/migrations/0010_auto_20181018_0822.py index 645ab1281d..4f39340123 100644 --- a/src/ralph/virtual/migrations/0010_auto_20181018_0822.py +++ b/src/ralph/virtual/migrations/0010_auto_20181018_0822.py @@ -5,20 +5,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0009_auto_20170522_0745'), + ("virtual", "0009_auto_20170522_0745"), ] operations = [ migrations.AddField( - model_name='cloudprovider', - name='cloud_sync_driver', + model_name="cloudprovider", + name="cloud_sync_driver", field=models.CharField(max_length=128, null=True, blank=True), ), migrations.AddField( - model_name='cloudprovider', - name='cloud_sync_enabled', + model_name="cloudprovider", + name="cloud_sync_enabled", field=models.BooleanField(default=False), ), ] diff --git a/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py b/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py index 825a1926d5..3a35b29be0 100644 --- a/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py +++ b/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py @@ -1,21 +1,27 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations import django_extensions.db.fields.json import django_cryptography.fields class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0010_auto_20181018_0822'), + ("virtual", "0010_auto_20181018_0822"), ] operations = [ migrations.AddField( - model_name='cloudprovider', - name='client_config', - field=django_cryptography.fields.encrypt(django_extensions.db.fields.json.JSONField(null=True, default=dict, blank=True, verbose_name='client configuration')), + model_name="cloudprovider", + name="client_config", + field=django_cryptography.fields.encrypt( + django_extensions.db.fields.json.JSONField( + null=True, + default=dict, + blank=True, + verbose_name="client configuration", + ) + ), ), ] diff --git a/src/ralph/virtual/migrations/0012_cloudimage.py b/src/ralph/virtual/migrations/0012_cloudimage.py index 5c57735adf..b299e2c236 100644 --- a/src/ralph/virtual/migrations/0012_cloudimage.py +++ b/src/ralph/virtual/migrations/0012_cloudimage.py @@ -6,22 +6,37 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0011_cloudprovider_client_config'), + ("virtual", "0011_cloudprovider_client_config"), ] operations = [ migrations.CreateModel( - name='CloudImage', + name="CloudImage", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('name', models.CharField(verbose_name='name', max_length=255, unique=True)), - ('image_id', models.CharField(verbose_name='image ID', max_length=100, unique=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ( + "name", + models.CharField(verbose_name="name", max_length=255, unique=True), + ), + ( + "image_id", + models.CharField( + verbose_name="image ID", max_length=100, unique=True + ), + ), ], options={ - 'verbose_name': 'Cloud image', - 'verbose_name_plural': 'Cloud images', + "verbose_name": "Cloud image", + "verbose_name_plural": "Cloud images", }, bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model), ), diff --git a/src/ralph/virtual/migrations/0013_auto_20190625_1239.py b/src/ralph/virtual/migrations/0013_auto_20190625_1239.py index 953b52b8cf..b9e1b28711 100644 --- a/src/ralph/virtual/migrations/0013_auto_20190625_1239.py +++ b/src/ralph/virtual/migrations/0013_auto_20190625_1239.py @@ -5,19 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0012_cloudimage'), + ("virtual", "0012_cloudimage"), ] operations = [ migrations.AlterModelOptions( - name='cloudimage', + name="cloudimage", options={}, ), migrations.AlterField( - model_name='cloudimage', - name='name', + model_name="cloudimage", + name="name", field=models.CharField(max_length=200), ), ] diff --git a/src/ralph/virtual/migrations/0014_auto_20240621_1009.py b/src/ralph/virtual/migrations/0014_auto_20240621_1009.py index cafbc27a75..a97e987fa2 100644 --- a/src/ralph/virtual/migrations/0014_auto_20240621_1009.py +++ b/src/ralph/virtual/migrations/0014_auto_20240621_1009.py @@ -7,16 +7,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0013_auto_20190625_1239'), + ("virtual", "0013_auto_20190625_1239"), ] operations = [ migrations.AlterModelManagers( - name='cloudflavor', + name="cloudflavor", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/virtual/migrations/0015_auto_20240621_1217.py b/src/ralph/virtual/migrations/0015_auto_20240621_1217.py index 04efd81be5..bfd8ac4c5a 100644 --- a/src/ralph/virtual/migrations/0015_auto_20240621_1217.py +++ b/src/ralph/virtual/migrations/0015_auto_20240621_1217.py @@ -5,28 +5,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('virtual', '0014_auto_20240621_1009'), + ("virtual", "0014_auto_20240621_1009"), ] operations = [ migrations.AlterModelManagers( - name='cloudhost', + name="cloudhost", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='cloudproject', + name="cloudproject", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), migrations.AlterModelManagers( - name='virtualserver', + name="virtualserver", managers=[ - ('polymorphic_objects', django.db.models.manager.Manager()), + ("polymorphic_objects", django.db.models.manager.Manager()), ], ), ] diff --git a/src/ralph/virtual/models.py b/src/ralph/virtual/models.py index 7f46d3d94a..ae4111a6bb 100644 --- a/src/ralph/virtual/models.py +++ b/src/ralph/virtual/models.py @@ -17,10 +17,7 @@ from ralph.assets.models.choices import ComponentType from ralph.assets.models.components import Component, ComponentModel, Ethernet from ralph.assets.utils import DNSaaSPublisherMixin -from ralph.data_center.models.physical import ( - DataCenterAsset, - NetworkableBaseObject -) +from ralph.data_center.models.physical import DataCenterAsset, NetworkableBaseObject from ralph.data_center.models.virtual import Cluster from ralph.data_center.publishers import publish_host_update from ralph.lib.mixins.fields import NullableCharField @@ -28,7 +25,7 @@ AdminAbsoluteUrlMixin, NamedMixin, PreviousStateMixin, - TimeStampMixin + TimeStampMixin, ) from ralph.lib.transitions.fields import TransitionField from ralph.networks.models.networks import IPAddress @@ -39,24 +36,22 @@ class CloudProvider(AdminAbsoluteUrlMixin, NamedMixin): class Meta: - verbose_name = _('Cloud provider') - verbose_name_plural = _('Cloud providers') + verbose_name = _("Cloud provider") + verbose_name_plural = _("Cloud providers") - cloud_sync_enabled = models.BooleanField( - null=False, blank=False, default=False - ) + cloud_sync_enabled = models.BooleanField(null=False, blank=False, default=False) cloud_sync_driver = models.CharField(max_length=128, null=True, blank=True) client_config = encrypt( JSONField( blank=True, null=True, - verbose_name='client configuration', + verbose_name="client configuration", ) ) class CloudFlavor(AdminAbsoluteUrlMixin, BaseObject): - name = models.CharField(_('name'), max_length=255) + name = models.CharField(_("name"), max_length=255) cloudprovider = models.ForeignKey(CloudProvider, on_delete=models.CASCADE) cloudprovider._autocomplete = False @@ -66,9 +61,9 @@ def __str__(self): return self.name def _set_component(self, model_args): - """ create/modify component cpu, mem or disk""" + """create/modify component cpu, mem or disk""" try: - model = ComponentModel.objects.get(name=model_args['name']) + model = ComponentModel.objects.get(name=model_args["name"]) except ObjectDoesNotExist: model = ComponentModel() for key, value in model_args.items(): @@ -78,7 +73,7 @@ def _set_component(self, model_args): VirtualComponent.objects.get(base_object=self, model=model) except ObjectDoesNotExist: for component in self.virtualcomponent_set.filter( - model__type=model_args['type'] + model__type=model_args["type"] ): component.delete() @@ -88,11 +83,13 @@ def _get_component(self, model_type, field_path): # use cached components if already prefetched (using prefetch_related) # otherwise, perform regular SQL query try: - components = self._prefetched_objects_cache['virtualcomponent_set'] + components = self._prefetched_objects_cache["virtualcomponent_set"] except (KeyError, AttributeError): - return self.virtualcomponent_set.filter( - model__type=model_type - ).values_list(field_path, flat=True).first() + return ( + self.virtualcomponent_set.filter(model__type=model_type) + .values_list(field_path, flat=True) + .first() + ) else: for component in components: if component.model.type == model_type: @@ -102,15 +99,15 @@ def _get_component(self, model_type, field_path): @property def cores(self): """Number of cores""" - return self._get_component(ComponentType.processor, 'model__cores') + return self._get_component(ComponentType.processor, "model__cores") @cores.setter def cores(self, new_cores): cpu = { - 'name': "{} cores vCPU".format(new_cores), - 'cores': new_cores, - 'family': 'vcpu', - 'type': ComponentType.processor + "name": "{} cores vCPU".format(new_cores), + "cores": new_cores, + "family": "vcpu", + "type": ComponentType.processor, } if self.cores != new_cores: self._set_component(cpu) @@ -118,14 +115,14 @@ def cores(self, new_cores): @property def memory(self): """RAM memory size in MiB""" - return self._get_component(ComponentType.memory, 'model__size') + return self._get_component(ComponentType.memory, "model__size") @memory.setter def memory(self, new_memory): ram = { - 'name': "{} MiB vMEM".format(new_memory), - 'size': new_memory, - 'type': ComponentType.memory, + "name": "{} MiB vMEM".format(new_memory), + "size": new_memory, + "type": ComponentType.memory, } if self.memory != new_memory: self._set_component(ram) @@ -133,14 +130,14 @@ def memory(self, new_memory): @property def disk(self): """Disk size in MiB""" - return self._get_component(ComponentType.disk, 'model__size') + return self._get_component(ComponentType.disk, "model__size") @disk.setter def disk(self, new_disk): disk = { - 'name': "{} GiB vHDD".format(int(new_disk / 1024)), - 'size': new_disk, - 'type': ComponentType.disk, + "name": "{} GiB vHDD".format(int(new_disk / 1024)), + "size": new_disk, + "type": ComponentType.disk, } if self.disk != new_disk: self._set_component(disk) @@ -149,31 +146,27 @@ def disk(self, new_disk): class CloudProject(PreviousStateMixin, AdminAbsoluteUrlMixin, BaseObject): cloudprovider = models.ForeignKey(CloudProvider, on_delete=models.CASCADE) cloudprovider._autocomplete = False - custom_fields_inheritance = OrderedDict([ - ('service_env', 'assets.ServiceEnvironment'), - ]) + custom_fields_inheritance = OrderedDict( + [ + ("service_env", "assets.ServiceEnvironment"), + ] + ) project_id = models.CharField( - verbose_name=_('project ID'), - unique=True, - max_length=100 + verbose_name=_("project ID"), unique=True, max_length=100 ) name = models.CharField(max_length=100) def __str__(self): - return 'Cloud Project: {}'.format(self.name) + return "Cloud Project: {}".format(self.name) class CloudImage(AdminAbsoluteUrlMixin, models.Model): - image_id = models.CharField( - verbose_name=_('image ID'), - unique=True, - max_length=100 - ) + image_id = models.CharField(verbose_name=_("image ID"), unique=True, max_length=100) name = models.CharField(max_length=200, unique=False) def __str__(self): - return 'Cloud Image: {}'.format(self.name) + return "Cloud Image: {}".format(self.name) @receiver(models.signals.post_save, sender=CloudProject) @@ -183,18 +176,19 @@ def update_service_env_on_cloudproject_save(sender, instance, **kwargs): instance.children.all().update(service_env=instance.service_env) -class CloudHost(PreviousStateMixin, - AdminAbsoluteUrlMixin, - NetworkableBaseObject, - BaseObject): +class CloudHost( + PreviousStateMixin, AdminAbsoluteUrlMixin, NetworkableBaseObject, BaseObject +): _allow_in_dashboard = True - previous_dc_host_update_fields = ['hostname'] - custom_fields_inheritance = OrderedDict([ - ('parent__cloudproject', 'virtual.CloudProject'), - ('configuration_path', 'assets.ConfigurationClass'), - ('configuration_path__module', 'assets.ConfigurationModule'), - ('service_env', 'assets.ServiceEnvironment'), - ]) + previous_dc_host_update_fields = ["hostname"] + custom_fields_inheritance = OrderedDict( + [ + ("parent__cloudproject", "virtual.CloudProject"), + ("configuration_path", "assets.ConfigurationClass"), + ("configuration_path__module", "assets.ConfigurationModule"), + ("service_env", "assets.ServiceEnvironment"), + ] + ) def save(self, *args, **kwargs): try: @@ -204,28 +198,21 @@ def save(self, *args, **kwargs): super(CloudHost, self).save(*args, **kwargs) cloudflavor = models.ForeignKey( - CloudFlavor, - verbose_name='Instance Type', - on_delete=models.CASCADE + CloudFlavor, verbose_name="Instance Type", on_delete=models.CASCADE ) cloudprovider = models.ForeignKey(CloudProvider, on_delete=models.CASCADE) cloudprovider._autocomplete = False - host_id = models.CharField( - verbose_name=_('host ID'), - unique=True, - max_length=100 + host_id = models.CharField(verbose_name=_("host ID"), unique=True, max_length=100) + hostname = models.CharField(verbose_name=_("hostname"), max_length=255) + hypervisor = models.ForeignKey( + DataCenterAsset, blank=True, null=True, on_delete=models.CASCADE ) - hostname = models.CharField( - verbose_name=_('hostname'), - max_length=255 - ) - hypervisor = models.ForeignKey(DataCenterAsset, blank=True, null=True, on_delete=models.CASCADE) image_name = models.CharField(max_length=255, null=True, blank=True) class Meta: - verbose_name = _('Cloud host') - verbose_name_plural = _('Cloud hosts') + verbose_name = _("Cloud host") + verbose_name_plural = _("Cloud hosts") def __str__(self): return self.hostname @@ -247,8 +234,8 @@ def ipaddresses(self): @property def ip_addresses(self): - return self.ethernet_set.select_related('ipaddress').values_list( - 'ipaddress__address', flat=True + return self.ethernet_set.select_related("ipaddress").values_list( + "ipaddress__address", flat=True ) @ip_addresses.setter @@ -263,15 +250,15 @@ def ip_addresses(self, value): new_ip.save() else: logger.warning( - 'Cannot assign IP %s to %s - it is already in use by ' - 'another asset', - ip, self.hostname + "Cannot assign IP %s to %s - it is already in use by " + "another asset", + ip, + self.hostname, ) except ObjectDoesNotExist: - logger.info('Creating new IP {} for {}'.format(ip, self)) + logger.info("Creating new IP {} for {}".format(ip, self)) new_ip = IPAddress( - ethernet=Ethernet.objects.create(base_object=self), - address=ip + ethernet=Ethernet.objects.create(base_object=self), address=ip ) new_ip.save() # refresh hostnames @@ -280,11 +267,11 @@ def ip_addresses(self, value): try: ip = IPAddress.objects.get(address=address) except IPAddress.DoesNotExist: - logger.debug('IP {} not found'.format(address)) + logger.debug("IP {} not found".format(address)) else: if ip.hostname != hostname: logger.info( - 'Setting {} for IP {} (previous value: {})'.format( + "Setting {} for IP {} (previous value: {})".format( hostname, address, ip.hostname ) ) @@ -293,7 +280,7 @@ def ip_addresses(self, value): to_delete = set(self.ip_addresses) - set(value) for ip in to_delete: - logger.warning('Deleting %s from %s', ip, self) + logger.warning("Deleting %s from %s", ip, self) Ethernet.objects.filter( base_object=self, ipaddress__address__in=to_delete ).delete() @@ -320,10 +307,7 @@ class VirtualComponent(Component): class VirtualServerType( - AdminAbsoluteUrlMixin, - NamedMixin, - TimeStampMixin, - models.Model + AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin, models.Model ): pass @@ -331,10 +315,10 @@ class VirtualServerType( class VirtualServerStatus(Choices): _ = Choices.Choice - new = _('new') - used = _('in use') - to_deploy = _('to deploy') - liquidated = _('liquidated') + new = _("new") + used = _("in use") + to_deploy = _("to deploy") + liquidated = _("liquidated") class VirtualServer( @@ -342,7 +326,7 @@ class VirtualServer( DNSaaSPublisherMixin, AdminAbsoluteUrlMixin, NetworkableBaseObject, - BaseObject + BaseObject, ): # parent field for VirtualServer is hypervisor! # TODO: limit parent to DataCenterAsset and CloudHost @@ -351,30 +335,30 @@ class VirtualServer( choices=VirtualServerStatus(), ) type = models.ForeignKey( - VirtualServerType, - related_name='virtual_servers', - on_delete=models.CASCADE + VirtualServerType, related_name="virtual_servers", on_delete=models.CASCADE ) hostname = NullableCharField( blank=True, default=None, max_length=255, null=True, - verbose_name=_('hostname'), + verbose_name=_("hostname"), unique=True, ) sn = NullableCharField( max_length=200, - verbose_name=_('SN'), + verbose_name=_("SN"), blank=True, default=None, null=True, unique=True, ) # TODO: remove this field - cluster = models.ForeignKey(Cluster, blank=True, null=True, on_delete=models.CASCADE) + cluster = models.ForeignKey( + Cluster, blank=True, null=True, on_delete=models.CASCADE + ) - previous_dc_host_update_fields = ['hostname'] + previous_dc_host_update_fields = ["hostname"] _allow_in_dashboard = True @cached_property @@ -383,10 +367,9 @@ def polymorphic_parent(self): def get_location(self): if ( - self.parent_id and - self.parent.content_type_id == ContentType.objects.get_for_model( - DataCenterAsset - ).id + self.parent_id + and self.parent.content_type_id + == ContentType.objects.get_for_model(DataCenterAsset).id ): parent = self.parent.asset.datacenterasset location = parent.get_location() @@ -408,16 +391,16 @@ def rack_id(self): def rack(self): if self.parent_id: polymorphic_parent = self.polymorphic_parent.last_descendant - if (isinstance(polymorphic_parent, (DataCenterAsset, CloudHost))): + if isinstance(polymorphic_parent, (DataCenterAsset, CloudHost)): return polymorphic_parent.rack return None class Meta: - verbose_name = _('Virtual server (VM)') - verbose_name_plural = _('Virtual servers (VM)') + verbose_name = _("Virtual server (VM)") + verbose_name_plural = _("Virtual servers (VM)") def __str__(self): - return 'VirtualServer: {} ({})'.format(self.hostname, self.sn) + return "VirtualServer: {} ({})".format(self.hostname, self.sn) post_commit(publish_host_update, VirtualServer) diff --git a/src/ralph/virtual/processors/noop.py b/src/ralph/virtual/processors/noop.py index 24c1be23fb..ab07a75fc6 100644 --- a/src/ralph/virtual/processors/noop.py +++ b/src/ralph/virtual/processors/noop.py @@ -6,4 +6,4 @@ def endpoint(cloud_provider, event_data): """The endpoint for DC asset synchronisation that does nothing.""" - logger.info('Received new DC asset synchronisation event. Doing nothing.') + logger.info("Received new DC asset synchronisation event. Doing nothing.") diff --git a/src/ralph/virtual/tests/factories.py b/src/ralph/virtual/tests/factories.py index 5119a96b54..e828a815fe 100644 --- a/src/ralph/virtual/tests/factories.py +++ b/src/ralph/virtual/tests/factories.py @@ -8,7 +8,7 @@ EthernetWithIPAddressFactory, MemoryFactory, ProcessorFactory, - ServiceEnvironmentFactory + ServiceEnvironmentFactory, ) from ralph.data_center.tests.factories import DataCenterAssetFactory from ralph.security.tests.factories import SecurityScanFactory @@ -19,104 +19,91 @@ CloudProject, CloudProvider, VirtualServer, - VirtualServerType + VirtualServerType, ) class CloudImageFactory(DjangoModelFactory): - - name = factory.Sequence(lambda n: 'image-{0}'.format(n)) - image_id = factory.Sequence(lambda n: 'img-uuid-{0}'.format(n)) + name = factory.Sequence(lambda n: "image-{0}".format(n)) + image_id = factory.Sequence(lambda n: "img-uuid-{0}".format(n)) class Meta: model = CloudImage - django_get_or_create = ['name', 'image_id'] + django_get_or_create = ["name", "image_id"] class CloudProviderFactory(DjangoModelFactory): - - name = factory.Iterator(['openstack', 'openstack2']) + name = factory.Iterator(["openstack", "openstack2"]) cloud_sync_enabled = False - cloud_sync_driver = factory.Iterator(['noop']) + cloud_sync_driver = factory.Iterator(["noop"]) class Meta: model = CloudProvider - django_get_or_create = ['name'] + django_get_or_create = ["name"] class CloudFlavorFactory(DjangoModelFactory): - - name = factory.Iterator(['flavor1', 'flavor2', 'flavor3']) - flavor_id = factory.Iterator(['flavor_id1', 'flavor_id2', 'flavor_id3']) - cloudprovider = factory.SubFactory( - CloudProviderFactory, - name='openstack' - ) + name = factory.Iterator(["flavor1", "flavor2", "flavor3"]) + flavor_id = factory.Iterator(["flavor_id1", "flavor_id2", "flavor_id3"]) + cloudprovider = factory.SubFactory(CloudProviderFactory, name="openstack") class Meta: model = CloudFlavor - django_get_or_create = ['flavor_id'] + django_get_or_create = ["flavor_id"] class CloudProjectFactory(DjangoModelFactory): - - name = factory.Iterator(['project1', 'project2', 'project3']) - project_id = factory.Iterator( - ['project_id1', 'project_id2', 'project_id3'] - ) + name = factory.Iterator(["project1", "project2", "project3"]) + project_id = factory.Iterator(["project_id1", "project_id2", "project_id3"]) cloudprovider = factory.SubFactory( CloudProviderFactory, - name='openstack', + name="openstack", ) service_env = factory.SubFactory(ServiceEnvironmentFactory) class Meta: model = CloudProject - django_get_or_create = ['project_id'] + django_get_or_create = ["project_id"] class CloudHostFactory(DjangoModelFactory): - cloudflavor = factory.SubFactory(CloudFlavorFactory) cloudprovider = factory.SubFactory( CloudProviderFactory, - name='openstack', + name="openstack", ) - host_id = factory.Sequence(lambda n: f'host_id1{n}.local') + host_id = factory.Sequence(lambda n: f"host_id1{n}.local") parent = factory.SubFactory(CloudProjectFactory) configuration_path = factory.SubFactory(ConfigurationClassFactory) service_env = factory.SubFactory(ServiceEnvironmentFactory) class Meta: model = CloudHost - django_get_or_create = ['host_id'] + django_get_or_create = ["host_id"] class CloudHostFullFactory(CloudHostFactory): hypervisor = factory.SubFactory(DataCenterAssetFactory) - securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object') - + securityscan = factory.RelatedFactory(SecurityScanFactory, "base_object") @factory.post_generation def post_tags(self, create, extracted, **kwargs): - self.tags.add('abc, cde', 'xyz') + self.tags.add("abc, cde", "xyz") class VirtualServerTypeFactory(DjangoModelFactory): - name = factory.Iterator( - ['XEN', 'VMWare', 'Hyper-V', 'Proxmox', 'VirtualBox'] - ) + name = factory.Iterator(["XEN", "VMWare", "Hyper-V", "Proxmox", "VirtualBox"]) class Meta: model = VirtualServerType - django_get_or_create = ['name'] + django_get_or_create = ["name"] class VirtualServerFactory(DjangoModelFactory): service_env = factory.SubFactory(ServiceEnvironmentFactory) - hostname = factory.Sequence(lambda n: 's{0:03d}.local'.format(n)) + hostname = factory.Sequence(lambda n: "s{0:03d}.local".format(n)) type = factory.SubFactory(VirtualServerTypeFactory) - sn = factory.Faker('ssn') + sn = factory.Faker("ssn") parent = factory.SubFactory(DataCenterAssetFactory) configuration_path = factory.SubFactory(ConfigurationClassFactory) @@ -125,28 +112,28 @@ class Meta: class VirtualServerFullFactory(VirtualServerFactory): - eth1 = factory.RelatedFactory(EthernetFactory, 'base_object') + eth1 = factory.RelatedFactory(EthernetFactory, "base_object") eth2 = factory.RelatedFactory( EthernetWithIPAddressFactory, - 'base_object', + "base_object", ipaddress__dhcp_expose=True, ) licence1 = factory.RelatedFactory( - 'ralph.licences.tests.factories.BaseObjectLicenceFactory', 'base_object' + "ralph.licences.tests.factories.BaseObjectLicenceFactory", "base_object" ) licence2 = factory.RelatedFactory( - 'ralph.licences.tests.factories.BaseObjectLicenceFactory', - 'base_object', - quantity=3 + "ralph.licences.tests.factories.BaseObjectLicenceFactory", + "base_object", + quantity=3, ) - mem1 = factory.RelatedFactory(MemoryFactory, 'base_object') - mem2 = factory.RelatedFactory(MemoryFactory, 'base_object') - proc1 = factory.RelatedFactory(ProcessorFactory, 'base_object') - proc2 = factory.RelatedFactory(ProcessorFactory, 'base_object') - disk1 = factory.RelatedFactory(DiskFactory, 'base_object') - disk2 = factory.RelatedFactory(DiskFactory, 'base_object') - securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object') + mem1 = factory.RelatedFactory(MemoryFactory, "base_object") + mem2 = factory.RelatedFactory(MemoryFactory, "base_object") + proc1 = factory.RelatedFactory(ProcessorFactory, "base_object") + proc2 = factory.RelatedFactory(ProcessorFactory, "base_object") + disk1 = factory.RelatedFactory(DiskFactory, "base_object") + disk2 = factory.RelatedFactory(DiskFactory, "base_object") + securityscan = factory.RelatedFactory(SecurityScanFactory, "base_object") @factory.post_generation def post_tags(self, create, extracted, **kwargs): - self.tags.add('abc, cde', 'xyz') + self.tags.add("abc, cde", "xyz") diff --git a/src/ralph/virtual/tests/samples/openstack_data.py b/src/ralph/virtual/tests/samples/openstack_data.py index 5aca7d2e7b..7f6673eb7b 100644 --- a/src/ralph/virtual/tests/samples/openstack_data.py +++ b/src/ralph/virtual/tests/samples/openstack_data.py @@ -1,143 +1,146 @@ # -*- coding: utf-8 -*- OPENSTACK_DATA = { - 'project_os_id1': { - 'name': 'project_os_1', - 'tags': ['tag1'], - 'servers': { - 'host_os_1': { - 'hostname': 'host_os_1', - 'hypervisor': 'hypervisor1.dcn.net', - 'flavor_id': 'flavor_os_id1', - 'tag': 'tag1', - 'ips': ['10.1.0.1', '10.2.0.1'], - 'created': '2015-09-10T06:48:00Z', - 'image': 'Ubuntu 14.04', - 'status': 'ACTIVE', + "project_os_id1": { + "name": "project_os_1", + "tags": ["tag1"], + "servers": { + "host_os_1": { + "hostname": "host_os_1", + "hypervisor": "hypervisor1.dcn.net", + "flavor_id": "flavor_os_id1", + "tag": "tag1", + "ips": ["10.1.0.1", "10.2.0.1"], + "created": "2015-09-10T06:48:00Z", + "image": "Ubuntu 14.04", + "status": "ACTIVE", }, - 'deleted': { - 'hostname': 'deleted', - 'hypervisor': 'hypervisor_os1.dcn.net', - 'flavor_id': 'flavor_id1', - 'tag': 'tag3', - 'ips': [], - 'created': '2015-09-16T06:48:00Z', - 'modified': '2015-10-16T06:48:03Z', - 'image': 'Ubuntu 14.04', - 'status': 'DELETED', + "deleted": { + "hostname": "deleted", + "hypervisor": "hypervisor_os1.dcn.net", + "flavor_id": "flavor_id1", + "tag": "tag3", + "ips": [], + "created": "2015-09-16T06:48:00Z", + "modified": "2015-10-16T06:48:03Z", + "image": "Ubuntu 14.04", + "status": "DELETED", }, - } + }, }, - 'project_os_id2': { - 'name': 'project_os_2', - 'tags': ['tag2'], - 'servers': { - 'host_os_2': { - 'hostname': 'host_os_2', - 'hypervisor': 'hypervisor1.dcn.net', - 'flavor_id': 'flavor_os_id2', - 'tag': 'tag2', - 'ips': ['10.3.0.1', '10.4.0.1'], - 'created': '2015-09-11T06:48:00Z', - 'image': 'Ubuntu 14.04', - 'status': 'ACTIVE', + "project_os_id2": { + "name": "project_os_2", + "tags": ["tag2"], + "servers": { + "host_os_2": { + "hostname": "host_os_2", + "hypervisor": "hypervisor1.dcn.net", + "flavor_id": "flavor_os_id2", + "tag": "tag2", + "ips": ["10.3.0.1", "10.4.0.1"], + "created": "2015-09-11T06:48:00Z", + "image": "Ubuntu 14.04", + "status": "ACTIVE", }, - 'host_os_3': { - 'hostname': 'host_os_3', - 'hypervisor': 'hypervisor1.dcn.net', - 'flavor_id': 'flavor_os_id1', - 'tag': 'tag2', - 'ips': ['10.10.10.10'], - 'created': '2015-09-12T06:48:00Z', - 'modified': '2015-10-12T06:48:03Z', - 'image': 'Ubuntu 15.04', - 'status': 'ACTIVE', - } - } + "host_os_3": { + "hostname": "host_os_3", + "hypervisor": "hypervisor1.dcn.net", + "flavor_id": "flavor_os_id1", + "tag": "tag2", + "ips": ["10.10.10.10"], + "created": "2015-09-12T06:48:00Z", + "modified": "2015-10-12T06:48:03Z", + "image": "Ubuntu 15.04", + "status": "ACTIVE", + }, + }, }, - 'project_os_id3': {'name': 'project_os_3', 'tags': ['tag1'], 'servers': {}}, - 'project_id1': {'name': 'modified1', 'tags': ['tag1'], 'servers': { - 'host_id_1': { - 'hostname': 'host_id_1', - 'hypervisor': 'hypervisor1.dcn.net', - 'flavor_id': 'flavor_os_id1', - 'tag': 'tag1', - 'ips': ['11.11.11.11'], - 'created': '2015-09-13T06:48:00Z', - 'modified': '2015-10-13T06:48:03Z', - 'image': 'CoreOS', - 'status': 'ACTIVE', + "project_os_id3": {"name": "project_os_3", "tags": ["tag1"], "servers": {}}, + "project_id1": { + "name": "modified1", + "tags": ["tag1"], + "servers": { + "host_id_1": { + "hostname": "host_id_1", + "hypervisor": "hypervisor1.dcn.net", + "flavor_id": "flavor_os_id1", + "tag": "tag1", + "ips": ["11.11.11.11"], + "created": "2015-09-13T06:48:00Z", + "modified": "2015-10-13T06:48:03Z", + "image": "CoreOS", + "status": "ACTIVE", } - } - } + }, + }, } OPENSTACK_FLAVORS = { - 'flavor_os_id1': { - 'name': 'm1-c2-d6', - 'cores': 2, - 'memory': 1024, - 'disk': 6144, - 'tag': 'ab' + "flavor_os_id1": { + "name": "m1-c2-d6", + "cores": 2, + "memory": 1024, + "disk": 6144, + "tag": "ab", + }, + "flavor_os_id2": { + "name": "m2-c8-d20", + "cores": 8, + "memory": 2048, + "disk": 20480, + "tag": "cd", }, - 'flavor_os_id2': { - 'name': 'm2-c8-d20', - 'cores': 8, - 'memory': 2048, - 'disk': 20480, - 'tag': 'cd' + "flavor_id1": { + "name": "change_1", + "cores": 4, + "memory": 4096, + "disk": 12288, + "tag": "ef", }, - 'flavor_id1': { - 'name': 'change_1', - 'cores': 4, - 'memory': 4096, - 'disk': 12288, - 'tag': 'ef' - } } OPENSTACK_INSTANCES = { - 'host_os_id1': { - 'hostname': 'host_test_1', - 'hypervisor': 'hypervisor_os1.dcn.net', - 'flavor_id': 'flavor_id1', - 'tag': 'tag2', - 'ips': ['10.10.10.10'], - 'created': '2015-09-14T06:48:00Z', - 'modified': '2015-10-14T06:48:03Z', - 'image': 'Ubuntu 14.04', - 'status': 'ACTIVE', + "host_os_id1": { + "hostname": "host_test_1", + "hypervisor": "hypervisor_os1.dcn.net", + "flavor_id": "flavor_id1", + "tag": "tag2", + "ips": ["10.10.10.10"], + "created": "2015-09-14T06:48:00Z", + "modified": "2015-10-14T06:48:03Z", + "image": "Ubuntu 14.04", + "status": "ACTIVE", }, - 'host_os_id2': { - 'hostname': 'host_test_2', - 'hypervisor': 'hypervisor_os1.dcn.net', - 'flavor_id': 'flavor_id1', - 'tag': 'tag3', - 'ips': ['10.10.10.11'], - 'created': '2015-09-15T06:48:00Z', - 'modified': '2015-10-15T06:48:03Z', - 'image': 'Fedora', - 'status': 'ACTIVE', + "host_os_id2": { + "hostname": "host_test_2", + "hypervisor": "hypervisor_os1.dcn.net", + "flavor_id": "flavor_id1", + "tag": "tag3", + "ips": ["10.10.10.11"], + "created": "2015-09-15T06:48:00Z", + "modified": "2015-10-15T06:48:03Z", + "image": "Fedora", + "status": "ACTIVE", }, - 'host_id1': { - 'hostname': 'host_mod_1', - 'hypervisor': 'hypervisor_os1.dcn.net', - 'flavor_id': 'flavor_id1', - 'tag': 'tag3', - 'ips': ['10.10.10.12'], - 'created': '2015-09-16T06:48:00Z', - 'modified': '2015-10-16T06:48:03Z', - 'image': 'Ubuntu 14.04', - 'status': 'ACTIVE', + "host_id1": { + "hostname": "host_mod_1", + "hypervisor": "hypervisor_os1.dcn.net", + "flavor_id": "flavor_id1", + "tag": "tag3", + "ips": ["10.10.10.12"], + "created": "2015-09-16T06:48:00Z", + "modified": "2015-10-16T06:48:03Z", + "image": "Ubuntu 14.04", + "status": "ACTIVE", }, - 'deleted': { - 'hostname': 'deleted', - 'hypervisor': 'hypervisor_os1.dcn.net', - 'flavor_id': 'flavor_id1', - 'tag': 'tag3', - 'ips': [], - 'created': '2015-09-16T06:48:00Z', - 'modified': '2015-10-16T06:48:03Z', - 'image': 'Ubuntu 14.04', - 'status': 'DELETED', + "deleted": { + "hostname": "deleted", + "hypervisor": "hypervisor_os1.dcn.net", + "flavor_id": "flavor_id1", + "tag": "tag3", + "ips": [], + "created": "2015-09-16T06:48:00Z", + "modified": "2015-10-16T06:48:03Z", + "image": "Ubuntu 14.04", + "status": "DELETED", }, } diff --git a/src/ralph/virtual/tests/test_admin.py b/src/ralph/virtual/tests/test_admin.py index adb8bc0481..6bc9f9b80a 100644 --- a/src/ralph/virtual/tests/test_admin.py +++ b/src/ralph/virtual/tests/test_admin.py @@ -1,82 +1,73 @@ # -*- coding: utf-8 -*- -import json from django.contrib.auth import get_user_model -from django.core.exceptions import ValidationError -from ralph.admin.sites import ralph_site -from ralph.assets.models.base import BaseObject from ralph.assets.tests.factories import BaseObjectFactory -from ralph.data_center.models import DataCenterAsset from ralph.data_center.tests.factories import ( DataCenterAssetFactory, - ServiceEnvironmentFactory + ServiceEnvironmentFactory, ) from ralph.licences.tests.factories import LicenceFactory from ralph.tests import RalphTestCase -from ralph.virtual.admin import VirtualServerAdmin, VirtualServerForm -from ralph.virtual.models import VirtualServer from ralph.virtual.tests.factories import CloudHostFactory, VirtualServerFactory class TestVirtualServerForm(RalphTestCase): def setUp(self): self.user = get_user_model().objects.create_superuser( - username='root', - password='password', - email='email@email.pl' + username="root", password="password", email="email@email.pl" ) - self.client.login(username='root', password='password') + self.client.login(username="root", password="password") self.virtual_server = VirtualServerFactory() self.url = self.virtual_server.get_absolute_url() def _add_management_data(self, data_dict): prefixes = ( - 'custom_fields-customfieldvalue-content_type-object_id-', - 'clusters-' - ) - postfixes = ('TOTAL_FORMS', 'INITIAL_FORMS') + "custom_fields-customfieldvalue-content_type-object_id-", + "clusters-", + ) + postfixes = ("TOTAL_FORMS", "INITIAL_FORMS") for pre in prefixes: for post in postfixes: - data_dict.update({ - '{}{}'.format(pre, post): 0 - }) + data_dict.update({"{}{}".format(pre, post): 0}) return data_dict def _get_basic_form_data(self): data = { - 'hostname': 'totally_random_new_hostname', - 'type': self.virtual_server.type.pk, - 'status': self.virtual_server.status, - 'service_env': self.virtual_server.service_env.pk + "hostname": "totally_random_new_hostname", + "type": self.virtual_server.type.pk, + "status": self.virtual_server.status, + "service_env": self.virtual_server.service_env.pk, } return self._add_management_data(data) def test_data_center_asset_parent(self): form_data = self._get_basic_form_data() - form_data['parent'] = DataCenterAssetFactory().pk + form_data["parent"] = DataCenterAssetFactory().pk response = self.client.post(self.url, form_data) self.assertEqual( response.status_code, 302, ( - repr(response.context['form'].errors) - if response.context and 'form' in response.context else '' - ) + repr(response.context["form"].errors) + if response.context and "form" in response.context + else "" + ), ) def test_cloud_host_parent(self): form_data = self._get_basic_form_data() - form_data['parent'] = CloudHostFactory().pk + form_data["parent"] = CloudHostFactory().pk response = self.client.post(self.url, form_data) self.assertEqual( response.status_code, 302, ( - repr(response.context['form'].errors) - if response.context and 'form' in response.context else '' - ) + repr(response.context["form"].errors) + if response.context and "form" in response.context + else "" + ), ) def test_invalid_hypervisor_type(self): @@ -85,19 +76,15 @@ def test_invalid_hypervisor_type(self): BaseObjectFactory(), ServiceEnvironmentFactory(), VirtualServerFactory(), - LicenceFactory() + LicenceFactory(), ): - form_data['parent'] = obj.pk + form_data["parent"] = obj.pk response = self.client.post(self.url, form_data) - self.assertTrue(response.context and response.context['errors']) - errors = response.context['form'].errors - self.assertEqual( - response.status_code, - 200, - repr(errors) - ) - self.assertIn('parent', errors.keys()) + self.assertTrue(response.context and response.context["errors"]) + errors = response.context["form"].errors + self.assertEqual(response.status_code, 200, repr(errors)) + self.assertIn("parent", errors.keys()) self.assertEqual( - errors['parent'], - ["Hypervisor must be one of DataCenterAsset or CloudHost"] + errors["parent"], + ["Hypervisor must be one of DataCenterAsset or CloudHost"], ) diff --git a/src/ralph/virtual/tests/test_api.py b/src/ralph/virtual/tests/test_api.py index 99740304b0..e6bf5c115c 100644 --- a/src/ralph/virtual/tests/test_api.py +++ b/src/ralph/virtual/tests/test_api.py @@ -9,12 +9,9 @@ from ralph.assets.tests.factories import ( EnvironmentFactory, EthernetFactory, - ServiceFactory -) -from ralph.data_center.tests.factories import ( - ClusterFactory, - DataCenterAssetFactory + ServiceFactory, ) +from ralph.data_center.tests.factories import ClusterFactory, DataCenterAssetFactory from ralph.lib.custom_fields.models import CustomField, CustomFieldTypes from ralph.networks.tests.factories import IPAddressFactory from ralph.virtual.models import ( @@ -24,7 +21,7 @@ CloudProvider, VirtualComponent, VirtualServer, - VirtualServerType + VirtualServerType, ) from ralph.virtual.tests.factories import ( CloudFlavorFactory, @@ -32,7 +29,7 @@ CloudHostFullFactory, CloudProjectFactory, CloudProviderFactory, - VirtualServerFullFactory + VirtualServerFullFactory, ) @@ -44,37 +41,36 @@ def setUp(self): self.services = ServiceFactory.create_batch(2) self.service_env = [] for i in range(0, 2): - self.service_env.append(ServiceEnvironment.objects.create( - service=self.services[i], environment=self.envs[i] - )) + self.service_env.append( + ServiceEnvironment.objects.create( + service=self.services[i], environment=self.envs[i] + ) + ) self.service_env[0].service.business_owners.set([self.user1]) self.service_env[0].service.technical_owners.set([self.user2]) self.service_env[0].save() - self.cloud_provider = CloudProviderFactory(name='openstack') + self.cloud_provider = CloudProviderFactory(name="openstack") self.cloud_flavor = CloudFlavorFactory() - self.cloud_project = CloudProjectFactory( - service_env=self.service_env[0] - ) + self.cloud_project = CloudProjectFactory(service_env=self.service_env[0]) self.cloud_host = CloudHostFactory( - parent=self.cloud_project, - cloudflavor=self.cloud_flavor + parent=self.cloud_project, cloudflavor=self.cloud_flavor ) self.cloud_host2 = CloudHostFactory() self.test_cpu = ComponentModel.objects.create( - name='vcpu1', + name="vcpu1", cores=5, - family='vCPU', + family="vCPU", type=ComponentType.processor, ) self.test_mem = ComponentModel.objects.create( - name='2000 MiB vMEM', - size='2000', + name="2000 MiB vMEM", + size="2000", type=ComponentType.memory, ) self.test_disk = ComponentModel.objects.create( - name='4 GiB vDISK', - size='4096', + name="4 GiB vDISK", + size="4096", type=ComponentType.disk, ) @@ -91,227 +87,217 @@ def setUp(self): model=self.test_disk, ) - @data('cloudflavor', 'cloudproject', 'cloudprovider') + @data("cloudflavor", "cloudproject", "cloudprovider") def test_get_list(self, field): - url = reverse(field + '-list') - response = self.client.get(url, format='json') + url = reverse(field + "-list") + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) def test_get_cloudhost_list(self): CloudHostFullFactory.create_batch(100) - url = reverse('cloudhost-list') + "?limit=100" + url = reverse("cloudhost-list") + "?limit=100" with self.assertQueriesMoreOrLess(14, plus_minus=1): - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data['results']), 100) - self.assertEqual(response.data['count'], 102) + self.assertEqual(len(response.data["results"]), 100) + self.assertEqual(response.data["count"], 102) @unpack @data( - ('cores', 5), - ('memory', 2000), - ('disk', 4096), + ("cores", 5), + ("memory", 2000), + ("disk", 4096), ) def test_get_cloudflavor_detail(self, field, value): - url = reverse('cloudflavor-detail', args=(self.cloud_flavor.id,)) - response = self.client.get(url, format='json') + url = reverse("cloudflavor-detail", args=(self.cloud_flavor.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data[field], value) def test_get_cloudhost_detail(self): - url = reverse('cloudhost-detail', args=(self.cloud_host.id,)) - response = self.client.get(url, format='json') + url = reverse("cloudhost-detail", args=(self.cloud_host.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['host_id'], self.cloud_host.host_id) - self.assertEqual(response.data['hostname'], self.cloud_host.hostname) - self.assertEqual(response.data['service_env']['id'], - self.cloud_host.service_env.id) - self.assertEqual(response.data['parent']['name'], - self.cloud_project.name) - self.assertEqual(response.data['cloudflavor']['cores'], - self.cloud_flavor.cores) - self.assertEqual(response.data['cloudflavor']['memory'], - self.cloud_flavor.memory) - self.assertEqual(response.data['cloudflavor']['disk'], - self.cloud_flavor.disk) - self.assertEqual(response.data['cloudflavor']['name'], - self.cloud_flavor.name) + self.assertEqual(response.data["host_id"], self.cloud_host.host_id) + self.assertEqual(response.data["hostname"], self.cloud_host.hostname) self.assertEqual( - response.data['business_owners'][0]['username'], 'user1' + response.data["service_env"]["id"], self.cloud_host.service_env.id ) + self.assertEqual(response.data["parent"]["name"], self.cloud_project.name) + self.assertEqual(response.data["cloudflavor"]["cores"], self.cloud_flavor.cores) self.assertEqual( - response.data['technical_owners'][0]['username'], 'user2' + response.data["cloudflavor"]["memory"], self.cloud_flavor.memory ) + self.assertEqual(response.data["cloudflavor"]["disk"], self.cloud_flavor.disk) + self.assertEqual(response.data["cloudflavor"]["name"], self.cloud_flavor.name) + self.assertEqual(response.data["business_owners"][0]["username"], "user1") + self.assertEqual(response.data["technical_owners"][0]["username"], "user2") def test_filter_cloudhost_by_service_uid(self): cloud_host = CloudHostFactory() - url = ( - reverse('cloudhost-list') + - '?service_env__service__uid={}'.format(cloud_host.service_env.service.uid) + url = reverse("cloudhost-list") + "?service_env__service__uid={}".format( + cloud_host.service_env.service.uid ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_get_cloudproject_detail(self): - url = reverse('cloudproject-detail', args=(self.cloud_project.id,)) - response = self.client.get(url, format='json') + url = reverse("cloudproject-detail", args=(self.cloud_project.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['id'], - self.cloud_project.id) - self.assertEqual(response.data['name'], - self.cloud_project.name) - self.assertEqual(response.data['service_env']['id'], - self.cloud_project.service_env.id) + self.assertEqual(response.data["id"], self.cloud_project.id) + self.assertEqual(response.data["name"], self.cloud_project.name) + self.assertEqual( + response.data["service_env"]["id"], self.cloud_project.service_env.id + ) def test_get_cloudprovider_detail(self): - url = reverse('cloudprovider-detail', args=(self.cloud_provider.id,)) - response = self.client.get(url, format='json') + url = reverse("cloudprovider-detail", args=(self.cloud_provider.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['name'], self.cloud_provider.name) + self.assertEqual(response.data["name"], self.cloud_provider.name) def test_create_cloudhost(self): - url = reverse('cloudhost-list') + url = reverse("cloudhost-list") args = { - 'cloudprovider': self.cloud_provider.id, - 'host_id': 'id_1', - 'hostname': 'name_1', - 'parent': self.cloud_project.id, - 'ip_addresses': ['10.0.0.1', '10.0.0.2'], - 'cloudflavor': self.cloud_flavor.id, - 'tags': ['prod', 'db'], + "cloudprovider": self.cloud_provider.id, + "host_id": "id_1", + "hostname": "name_1", + "parent": self.cloud_project.id, + "ip_addresses": ["10.0.0.1", "10.0.0.2"], + "cloudflavor": self.cloud_flavor.id, + "tags": ["prod", "db"], } - response = self.client.post(url, args, format='json') + response = self.client.post(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - host = CloudHost.objects.get(host_id=args['host_id']) + host = CloudHost.objects.get(host_id=args["host_id"]) self.assertEqual(host.cloudprovider, self.cloud_provider) - self.assertEqual(host.host_id, args['host_id']) - self.assertEqual(host.hostname, args['hostname']) + self.assertEqual(host.host_id, args["host_id"]) + self.assertEqual(host.hostname, args["hostname"]) self.assertEqual(host.parent.id, self.cloud_project.id) self.assertEqual(host.cloudflavor, self.cloud_flavor) - self.assertEqual(set(host.tags.names()), set(args['tags'])) + self.assertEqual(set(host.tags.names()), set(args["tags"])) self.assertEqual(host.service_env, self.service_env[0]) - self.assertEqual(set(host.ip_addresses), set(args['ip_addresses'])) + self.assertEqual(set(host.ip_addresses), set(args["ip_addresses"])) def test_create_cloudflavor(self): - url = reverse('cloudflavor-list') + url = reverse("cloudflavor-list") args = { - 'flavor_id': 'id1', - 'name': 'name_2', - 'cores': 4, - 'memory': 1024, - 'disk': 10240, - 'tags': ['prod', 'db'], - 'cloudprovider': self.cloud_provider.id, + "flavor_id": "id1", + "name": "name_2", + "cores": 4, + "memory": 1024, + "disk": 10240, + "tags": ["prod", "db"], + "cloudprovider": self.cloud_provider.id, } - response = self.client.post(url, args, format='json') + response = self.client.post(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - flavor = CloudFlavor.objects.get(name=args['name']) + flavor = CloudFlavor.objects.get(name=args["name"]) self.assertEqual(flavor.cloudprovider, self.cloud_provider) - self.assertEqual(flavor.flavor_id, args['flavor_id']) - self.assertEqual(flavor.name, args['name']) - self.assertEqual(flavor.cores, args['cores']) - self.assertEqual(flavor.memory, args['memory']) - self.assertEqual(flavor.disk, args['disk']) - self.assertEqual(set(flavor.tags.names()), set(args['tags'])) + self.assertEqual(flavor.flavor_id, args["flavor_id"]) + self.assertEqual(flavor.name, args["name"]) + self.assertEqual(flavor.cores, args["cores"]) + self.assertEqual(flavor.memory, args["memory"]) + self.assertEqual(flavor.disk, args["disk"]) + self.assertEqual(set(flavor.tags.names()), set(args["tags"])) def test_create_cloudproject(self): - url = reverse('cloudproject-list') + url = reverse("cloudproject-list") args = { - 'cloudprovider': self.cloud_provider.id, - 'project_id': 'id_1', - 'name': 'name_1', - 'service_env': self.service_env[0].id, - 'tags': ['prod', 'db'], + "cloudprovider": self.cloud_provider.id, + "project_id": "id_1", + "name": "name_1", + "service_env": self.service_env[0].id, + "tags": ["prod", "db"], } - response = self.client.post(url, args, format='json') + response = self.client.post(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - project = CloudProject.objects.get(project_id=args['project_id']) + project = CloudProject.objects.get(project_id=args["project_id"]) self.assertEqual(project.cloudprovider, self.cloud_provider) - self.assertEqual(project.project_id, args['project_id']) - self.assertEqual(project.name, args['name']) - self.assertEqual(set(project.tags.names()), set(args['tags'])) + self.assertEqual(project.project_id, args["project_id"]) + self.assertEqual(project.name, args["name"]) + self.assertEqual(set(project.tags.names()), set(args["tags"])) self.assertEqual(project.service_env, self.service_env[0]) def test_create_cloudprovider(self): - url = reverse('cloudprovider-list') - args = {'name': 'test1'} - response = self.client.post(url, args, format='json') + url = reverse("cloudprovider-list") + args = {"name": "test1"} + response = self.client.post(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - provider = CloudProvider.objects.get(name=args['name']) - self.assertEqual(provider.name, args['name']) + provider = CloudProvider.objects.get(name=args["name"]) + self.assertEqual(provider.name, args["name"]) def test_patch_cloudhost(self): - url = reverse('cloudhost-detail', args=(self.cloud_host.id,)) + url = reverse("cloudhost-detail", args=(self.cloud_host.id,)) args = { - 'cloudprovider': self.cloud_provider.id, - 'host_id': 'id_1', - 'hostname': 'name_1', - 'parent': self.cloud_project.id, - 'ip_addresses': ['10.0.0.1', '10.0.0.2'], - 'cloudflavor': self.cloud_flavor.id, - 'tags': ['prod', 'db'], + "cloudprovider": self.cloud_provider.id, + "host_id": "id_1", + "hostname": "name_1", + "parent": self.cloud_project.id, + "ip_addresses": ["10.0.0.1", "10.0.0.2"], + "cloudflavor": self.cloud_flavor.id, + "tags": ["prod", "db"], } - response = self.client.patch(url, args, format='json') + response = self.client.patch(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - host = CloudHost.objects.get(host_id=args['host_id']) + host = CloudHost.objects.get(host_id=args["host_id"]) self.assertEqual(host.cloudprovider, self.cloud_provider) - self.assertEqual(host.host_id, args['host_id']) - self.assertEqual(host.hostname, args['hostname']) + self.assertEqual(host.host_id, args["host_id"]) + self.assertEqual(host.hostname, args["hostname"]) self.assertEqual(host.parent.id, self.cloud_project.id) self.assertEqual(host.cloudflavor, self.cloud_flavor) - self.assertEqual(set(host.tags.names()), set(args['tags'])) - self.assertEqual(set(host.ip_addresses), set(args['ip_addresses'])) + self.assertEqual(set(host.tags.names()), set(args["tags"])) + self.assertEqual(set(host.ip_addresses), set(args["ip_addresses"])) def test_patch_cloudflavor(self): - url = reverse('cloudflavor-detail', args=(self.cloud_flavor.id,)) + url = reverse("cloudflavor-detail", args=(self.cloud_flavor.id,)) args = { - 'flavor_id': 'id1', - 'name': 'name_2', - 'cores': 4, - 'memory': 1024, - 'disk': 10240, - 'tags': ['prod', 'db'], - 'cloudprovider': self.cloud_provider.id, + "flavor_id": "id1", + "name": "name_2", + "cores": 4, + "memory": 1024, + "disk": 10240, + "tags": ["prod", "db"], + "cloudprovider": self.cloud_provider.id, } - response = self.client.patch(url, args, format='json') + response = self.client.patch(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - flavor = CloudFlavor.objects.get(name=args['name']) + flavor = CloudFlavor.objects.get(name=args["name"]) self.assertEqual(flavor.cloudprovider, self.cloud_provider) - self.assertEqual(flavor.flavor_id, args['flavor_id']) - self.assertEqual(flavor.name, args['name']) - self.assertEqual(flavor.cores, args['cores']) - self.assertEqual(flavor.memory, args['memory']) - self.assertEqual(flavor.disk, args['disk']) - self.assertEqual(set(flavor.tags.names()), set(args['tags'])) + self.assertEqual(flavor.flavor_id, args["flavor_id"]) + self.assertEqual(flavor.name, args["name"]) + self.assertEqual(flavor.cores, args["cores"]) + self.assertEqual(flavor.memory, args["memory"]) + self.assertEqual(flavor.disk, args["disk"]) + self.assertEqual(set(flavor.tags.names()), set(args["tags"])) def test_patch_cloudproject(self): - url = reverse('cloudproject-detail', args=(self.cloud_project.id,)) + url = reverse("cloudproject-detail", args=(self.cloud_project.id,)) args = { - 'cloudprovider': self.cloud_provider.id, - 'project_id': 'id_1', - 'name': 'name_1', - 'service_env': self.service_env[1].id, - 'tags': ['prod', 'db'], + "cloudprovider": self.cloud_provider.id, + "project_id": "id_1", + "name": "name_1", + "service_env": self.service_env[1].id, + "tags": ["prod", "db"], } - response = self.client.patch(url, args, format='json') + response = self.client.patch(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - project = CloudProject.objects.get(project_id=args['project_id']) + project = CloudProject.objects.get(project_id=args["project_id"]) self.assertEqual(project.cloudprovider, self.cloud_provider) - self.assertEqual(project.project_id, args['project_id']) - self.assertEqual(project.name, args['name']) - self.assertEqual(set(project.tags.names()), set(args['tags'])) + self.assertEqual(project.project_id, args["project_id"]) + self.assertEqual(project.name, args["name"]) + self.assertEqual(set(project.tags.names()), set(args["tags"])) self.assertEqual(project.service_env, self.service_env[1]) def test_patch_cloudprovider(self): - url = reverse('cloudprovider-detail', args=(self.cloud_provider.id,)) - args = {'name': 'test1'} - response = self.client.patch(url, args, format='json') + url = reverse("cloudprovider-detail", args=(self.cloud_provider.id,)) + args = {"name": "test1"} + response = self.client.patch(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - provider = CloudProvider.objects.get(name=args['name']) - self.assertEqual(provider.name, args['name']) + provider = CloudProvider.objects.get(name=args["name"]) + self.assertEqual(provider.name, args["name"]) def test_delete_cloud_flavor_returns_409_if_is_used_by_cloud_hosts(self): # given @@ -319,33 +305,27 @@ def test_delete_cloud_flavor_returns_409_if_is_used_by_cloud_hosts(self): CloudHostFactory(cloudflavor=cloud_flavor) # when - url = reverse('cloudflavor-detail', args=(cloud_flavor.pk,)) + url = reverse("cloudflavor-detail", args=(cloud_flavor.pk,)) resp = self.client.delete(url) # then self.assertEqual(resp.status_code, status.HTTP_409_CONFLICT) self.assertIn( - 'Cloud flavor is in use and hence is not deletable.', - resp.data['detail'] - ) - self.assertTrue( - CloudFlavor.objects.filter(pk=cloud_flavor.pk).exists() + "Cloud flavor is in use and hence is not deletable.", resp.data["detail"] ) + self.assertTrue(CloudFlavor.objects.filter(pk=cloud_flavor.pk).exists()) def test_unused_cloud_flavor_can_be_deleted(self): # given cloud_flavor = CloudFlavorFactory() # when - url = reverse('cloudflavor-detail', args=(cloud_flavor.pk,)) + url = reverse("cloudflavor-detail", args=(cloud_flavor.pk,)) resp = self.client.delete(url) # then self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT) - self.assertRaises( - CloudFlavor.DoesNotExist, - cloud_flavor.refresh_from_db - ) + self.assertRaises(CloudFlavor.DoesNotExist, cloud_flavor.refresh_from_db) def test_used_cloud_flavor_can_be_deleted_with_force(self): # given @@ -353,80 +333,64 @@ def test_used_cloud_flavor_can_be_deleted_with_force(self): CloudHostFactory(cloudflavor=cloud_flavor) # when - url = reverse('cloudflavor-detail', args=(cloud_flavor.pk,)) - data = {'force': True} + url = reverse("cloudflavor-detail", args=(cloud_flavor.pk,)) + data = {"force": True} resp = self.client.delete(url, data=data) # then self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT) - self.assertRaises( - CloudFlavor.DoesNotExist, - cloud_flavor.refresh_from_db - ) + self.assertRaises(CloudFlavor.DoesNotExist, cloud_flavor.refresh_from_db) @data(CloudFlavorFactory, CloudHostFactory, CloudProjectFactory) - def test_delete_cloud_provider_returns_409_if_has_child_objects( - self, child_type - ): + def test_delete_cloud_provider_returns_409_if_has_child_objects(self, child_type): # given cloud_provider = CloudProviderFactory(name="test-cloud-provider") child_type(cloudprovider=cloud_provider) # when - url = reverse('cloudprovider-detail', args=(cloud_provider.pk,)) + url = reverse("cloudprovider-detail", args=(cloud_provider.pk,)) resp = self.client.delete(url) # then self.assertEqual(resp.status_code, status.HTTP_409_CONFLICT) self.assertIn( - 'Cloud provider is in use and hence is not deletable.', - resp.data['detail'] - ) - self.assertTrue( - CloudProvider.objects.filter(pk=cloud_provider.pk).exists() + "Cloud provider is in use and hence is not deletable.", resp.data["detail"] ) + self.assertTrue(CloudProvider.objects.filter(pk=cloud_provider.pk).exists()) def test_empty_cloud_provider_can_be_deleted(self): # given cloud_provider = CloudProviderFactory(name="test-cloud-provider") # when - url = reverse('cloudprovider-detail', args=(cloud_provider.pk,)) + url = reverse("cloudprovider-detail", args=(cloud_provider.pk,)) resp = self.client.delete(url) # then self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT) - self.assertRaises( - CloudProvider.DoesNotExist, - cloud_provider.refresh_from_db - ) + self.assertRaises(CloudProvider.DoesNotExist, cloud_provider.refresh_from_db) @data(CloudFlavorFactory, CloudHostFactory, CloudProjectFactory) - def test_non_empty_cloud_provider_can_be_deleted_with_force( - self, child_type - ): + def test_non_empty_cloud_provider_can_be_deleted_with_force(self, child_type): # given cloud_provider = CloudProviderFactory(name="test-cloud-provider") child_type(cloudprovider=cloud_provider) # when - url = reverse('cloudprovider-detail', args=(cloud_provider.pk,)) - data = {'force': True} + url = reverse("cloudprovider-detail", args=(cloud_provider.pk,)) + data = {"force": True} resp = self.client.delete(url, data=data) # then self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT) - self.assertRaises( - CloudProvider.DoesNotExist, - cloud_provider.refresh_from_db - ) + self.assertRaises(CloudProvider.DoesNotExist, cloud_provider.refresh_from_db) def test_inheritance_of_service_env_on_change_in_a_cloud_project(self): - url = reverse('cloudproject-detail', args=(self.cloud_project.id,)) + url = reverse("cloudproject-detail", args=(self.cloud_project.id,)) args = { - 'service_env': self.service_env[1].id, + "service_env": self.service_env[1].id, } - response = self.client.patch(url, args, format='json') + response = self.client.patch(url, args, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) host = CloudHost.objects.get(host_id=self.cloud_host.host_id) self.assertEqual(host.service_env, self.service_env[1]) @@ -438,11 +402,11 @@ def setUp(self): self.hypervisor = DataCenterAssetFactory() self.cloud_hypervisor = CloudHostFactory() self.cluster = ClusterFactory() - self.type = VirtualServerType.objects.create(name='XEN') + self.type = VirtualServerType.objects.create(name="XEN") self.virtual_server = VirtualServerFullFactory( - service_env__environment__name='some_env', + service_env__environment__name="some_env", ) - self.virtual_server.parent.service_env.service.uid = 's-12345' + self.virtual_server.parent.service_env.service.uid = "s-12345" self.virtual_server.parent.service_env.service.save() self.virtual_server.service_env.service.business_owners.set([self.user1]) self.virtual_server.service_env.service.technical_owners.set([self.user2]) @@ -454,203 +418,162 @@ def setUp(self): def test_get_virtual_server_list(self): VirtualServerFullFactory.create_batch(20) - url = reverse('virtualserver-list') + "?limit=100" + url = reverse("virtualserver-list") + "?limit=100" with self.assertNumQueries(16): - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['count'], 22) + self.assertEqual(response.data["count"], 22) def test_get_virtual_server_details(self): - url = reverse('virtualserver-detail', args=(self.virtual_server.id,)) - response = self.client.get(url, format='json') + url = reverse("virtualserver-detail", args=(self.virtual_server.id,)) + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['hostname'], - self.virtual_server.hostname - ) - self.assertEqual(len(response.data['ethernet']), 2) + self.assertEqual(response.data["hostname"], self.virtual_server.hostname) + self.assertEqual(len(response.data["ethernet"]), 2) self.assertCountEqual( [ - eth['ipaddress']['address'] - for eth in response.data['ethernet'] - if eth['ipaddress'] + eth["ipaddress"]["address"] + for eth in response.data["ethernet"] + if eth["ipaddress"] ], - self.virtual_server.ipaddresses.values_list('address', flat=True) - ) - self.assertEqual(len(response.data['memory']), 2) - self.assertEqual(response.data['memory'][0]['speed'], 1600) - self.assertEqual(response.data['memory'][0]['size'], 8192) - self.assertEqual( - response.data['business_owners'][0]['username'], 'user1' - ) - self.assertEqual( - response.data['technical_owners'][0]['username'], 'user2' + self.virtual_server.ipaddresses.values_list("address", flat=True), ) + self.assertEqual(len(response.data["memory"]), 2) + self.assertEqual(response.data["memory"][0]["speed"], 1600) + self.assertEqual(response.data["memory"][0]["size"], 8192) + self.assertEqual(response.data["business_owners"][0]["username"], "user1") + self.assertEqual(response.data["technical_owners"][0]["username"], "user2") def test_create_virtual_server(self): virtual_server_count = VirtualServer.objects.count() - url = reverse('virtualserver-list') + url = reverse("virtualserver-list") data = { - 'hostname': 's1234.local', - 'type': self.type.id, - 'sn': '143ed36a-3e86-457d-9e19-3dcfe4d5ed26', - 'hypervisor': self.hypervisor.id, + "hostname": "s1234.local", + "type": self.type.id, + "sn": "143ed36a-3e86-457d-9e19-3dcfe4d5ed26", + "hypervisor": self.hypervisor.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual( - VirtualServer.objects.count(), virtual_server_count + 1 - ) - virtual_server = VirtualServer.objects.get(pk=response.data['id']) - self.assertEqual(virtual_server.hostname, data['hostname']) + self.assertEqual(VirtualServer.objects.count(), virtual_server_count + 1) + virtual_server = VirtualServer.objects.get(pk=response.data["id"]) + self.assertEqual(virtual_server.hostname, data["hostname"]) self.assertEqual(virtual_server.parent.id, self.hypervisor.id) - self.assertEqual(virtual_server.sn, data['sn']) + self.assertEqual(virtual_server.sn, data["sn"]) def test_create_virtual_server_with_cloud_host_as_parent(self): virtual_server_count = VirtualServer.objects.count() - url = reverse('virtualserver-list') + url = reverse("virtualserver-list") data = { - 'hostname': 's1234.local', - 'type': self.type.id, - 'sn': '143ed36a-3e86-457d-9e19-3dcfe4d5ed26', - 'hypervisor': self.cloud_hypervisor.id, + "hostname": "s1234.local", + "type": self.type.id, + "sn": "143ed36a-3e86-457d-9e19-3dcfe4d5ed26", + "hypervisor": self.cloud_hypervisor.id, } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual( - VirtualServer.objects.count(), virtual_server_count + 1 - ) - virtual_server = VirtualServer.objects.get(pk=response.data['id']) - self.assertEqual(virtual_server.hostname, data['hostname']) + self.assertEqual(VirtualServer.objects.count(), virtual_server_count + 1) + virtual_server = VirtualServer.objects.get(pk=response.data["id"]) + self.assertEqual(virtual_server.hostname, data["hostname"]) self.assertEqual(virtual_server.parent.id, self.cloud_hypervisor.id) - self.assertEqual(virtual_server.sn, data['sn']) + self.assertEqual(virtual_server.sn, data["sn"]) def test_patch_virtual_server(self): - url = reverse('virtualserver-detail', args=(self.virtual_server.id,)) - data = { - 'hostname': 's111111.local' - } - response = self.client.patch(url, data, format='json') + url = reverse("virtualserver-detail", args=(self.virtual_server.id,)) + data = {"hostname": "s111111.local"} + response = self.client.patch(url, data, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.virtual_server.refresh_from_db() - self.assertEqual(self.virtual_server.hostname, 's111111.local') + self.assertEqual(self.virtual_server.hostname, "s111111.local") def test_add_custom_field_to_virtual_server(self): cf = CustomField.objects.create( - name='test str', type=CustomFieldTypes.STRING, default_value='xyz' + name="test str", type=CustomFieldTypes.STRING, default_value="xyz" + ) + url = ( + reverse("virtualserver-detail", args=(self.virtual_server.id,)) + + "customfields/" ) - url = reverse('virtualserver-detail', args=(self.virtual_server.id,)) + "customfields/" data = { - 'custom_field': cf.id, - 'value': 'new_value', + "custom_field": cf.id, + "value": "new_value", } response = self.client.post(url, data=data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_filter_by_configuration_path(self): - url = reverse('virtualserver-list') + '?configuration_path={}'.format( + url = reverse("virtualserver-list") + "?configuration_path={}".format( self.virtual_server.configuration_path.path, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_hostname(self): - url = reverse('virtualserver-list') + '?hostname={}'.format( + url = reverse("virtualserver-list") + "?hostname={}".format( self.virtual_server.hostname, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_ip_address(self): - url = reverse('virtualserver-list') + '?ip={}'.format( + url = reverse("virtualserver-list") + "?ip={}".format( self.ip.address, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_uid(self): - url = reverse('virtualserver-list') + '?service={}'.format( + url = reverse("virtualserver-list") + "?service={}".format( self.virtual_server.service_env.service.uid, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_uid2(self): - url = ( - reverse('virtualserver-list') + - '?service_env__service__uid={}'.format( - self.virtual_server.service_env.service.uid, - ) + url = reverse("virtualserver-list") + "?service_env__service__uid={}".format( + self.virtual_server.service_env.service.uid, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_id(self): - url = ( - reverse('virtualserver-list') + - '?service_env__service__id={}'.format( - self.virtual_server.service_env.service.id, - ) + url = reverse("virtualserver-list") + "?service_env__service__id={}".format( + self.virtual_server.service_env.service.id, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_name(self): - url = reverse('virtualserver-list') + '?service={}'.format( + url = reverse("virtualserver-list") + "?service={}".format( self.virtual_server.service_env.service.name, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_service_name2(self): - url = ( - reverse('virtualserver-list') + - '?service_env__service__name={}'.format( - self.virtual_server.service_env.service.name, - ) + url = reverse("virtualserver-list") + "?service_env__service__name={}".format( + self.virtual_server.service_env.service.name, ) - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_env_name(self): - url = reverse('virtualserver-list') + '?env=some_env' - response = self.client.get(url, format='json') + url = reverse("virtualserver-list") + "?env=some_env" + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) + self.assertEqual(response.data["count"], 1) def test_filter_by_hypervisor_service(self): - url = reverse('virtualserver-list') + '?hypervisor_service=s-12345' - response = self.client.get(url, format='json') + url = reverse("virtualserver-list") + "?hypervisor_service=s-12345" + response = self.client.get(url, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data['count'], 1 - ) - self.assertEqual( - response.data['results'][0]['id'], self.virtual_server.id - ) + self.assertEqual(response.data["count"], 1) + self.assertEqual(response.data["results"][0]["id"], self.virtual_server.id) diff --git a/src/ralph/virtual/tests/test_cloudsync.py b/src/ralph/virtual/tests/test_cloudsync.py index f2058ae7ef..18413c2ce2 100644 --- a/src/ralph/virtual/tests/test_cloudsync.py +++ b/src/ralph/virtual/tests/test_cloudsync.py @@ -8,83 +8,75 @@ class TestCloudSyncRouter(RalphAPITestCase): - def setUp(self): super().setUp() cloudsync.load_processors() def test_event_routed_correctly(self): - processor_name = 'proucessah' + processor_name = "proucessah" cloud_provider = CloudProviderFactory( - cloud_sync_enabled=True, - cloud_sync_driver=processor_name + cloud_sync_enabled=True, cloud_sync_driver=processor_name ) cloudsync.CLOUD_SYNC_DRIVERS[processor_name] = Mock() - test_data = {'test': True} + test_data = {"test": True} - url = reverse('cloud-sync-router', args=(cloud_provider.id,)) - self.client.post(url, test_data, format='json') + url = reverse("cloud-sync-router", args=(cloud_provider.id,)) + self.client.post(url, test_data, format="json") - cloudsync.CLOUD_SYNC_DRIVERS[ - processor_name - ].assert_called_once_with(cloud_provider, test_data) + cloudsync.CLOUD_SYNC_DRIVERS[processor_name].assert_called_once_with( + cloud_provider, test_data + ) def test_404_bad_provider_id(self): bad_provider_id = 42 - url = reverse('cloud-sync-router', args=(bad_provider_id,)) - resp = self.client.post(url, {}, format='json') + url = reverse("cloud-sync-router", args=(bad_provider_id,)) + resp = self.client.post(url, {}, format="json") self.assertEqual(404, resp.status_code) def test_404_sync_disabled(self): cloud_provider = CloudProviderFactory(cloud_sync_enabled=False) - url = reverse('cloud-sync-router', args=(cloud_provider.id,)) - resp = self.client.post(url, {}, format='json') + url = reverse("cloud-sync-router", args=(cloud_provider.id,)) + resp = self.client.post(url, {}, format="json") self.assertEqual(404, resp.status_code) def test_404_processor_not_set(self): cloud_provider = CloudProviderFactory( - cloud_sync_enabled=True, - cloud_sync_driver=None + cloud_sync_enabled=True, cloud_sync_driver=None ) - url = reverse('cloud-sync-router', args=(cloud_provider.id,)) - resp = self.client.post(url, {}, format='json') + url = reverse("cloud-sync-router", args=(cloud_provider.id,)) + resp = self.client.post(url, {}, format="json") self.assertEqual(404, resp.status_code) def test_400_bad_json(self): - processor_name = 'proucessah' + processor_name = "proucessah" cloud_provider = CloudProviderFactory( - cloud_sync_enabled=True, - cloud_sync_driver=processor_name + cloud_sync_enabled=True, cloud_sync_driver=processor_name ) cloudsync.CLOUD_SYNC_DRIVERS[processor_name] = Mock() test_data = None - url = reverse('cloud-sync-router', args=(cloud_provider.id,)) + url = reverse("cloud-sync-router", args=(cloud_provider.id,)) resp = self.client.post(url, test_data) self.assertEqual(400, resp.status_code) - self.assertEqual( - 0, - cloudsync.CLOUD_SYNC_DRIVERS[processor_name].call_count - ) + self.assertEqual(0, cloudsync.CLOUD_SYNC_DRIVERS[processor_name].call_count) def test_501_processor_not_available(self): cloud_provider = CloudProviderFactory( - cloud_sync_enabled=True, - cloud_sync_driver='CloudSyncProcessorFactory' + cloud_sync_enabled=True, cloud_sync_driver="CloudSyncProcessorFactory" ) - url = reverse('cloud-sync-router', args=(cloud_provider.id,)) - resp = self.client.post(url, {}, format='json') + url = reverse("cloud-sync-router", args=(cloud_provider.id,)) + resp = self.client.post(url, {}, format="json") self.assertEqual(501, resp.status_code) - self.assertEqual(b'Specified processor is not available', resp.content) + self.assertEqual(b"Specified processor is not available", resp.content) diff --git a/src/ralph/virtual/tests/test_models.py b/src/ralph/virtual/tests/test_models.py index ae5d000d88..6d0e7c4ca7 100644 --- a/src/ralph/virtual/tests/test_models.py +++ b/src/ralph/virtual/tests/test_models.py @@ -1,4 +1,3 @@ -from datetime import datetime from ddt import data, ddt, unpack @@ -8,20 +7,16 @@ from ralph.assets.tests.factories import ( EnvironmentFactory, ServiceEnvironmentFactory, - ServiceFactory -) -from ralph.data_center.tests.factories import ( - DataCenterAssetFullFactory, - RackFactory + ServiceFactory, ) +from ralph.data_center.tests.factories import DataCenterAssetFullFactory, RackFactory from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue + CustomFieldValue, ) from ralph.networks.models import IPAddress from ralph.networks.tests.factories import NetworkFactory -from ralph.security.models import ScanStatus from ralph.security.tests.factories import SecurityScanFactory from ralph.tests import RalphTestCase from ralph.virtual.models import CloudHost, VirtualComponent, VirtualServer @@ -30,7 +25,7 @@ CloudHostFactory, CloudProjectFactory, CloudProviderFactory, - VirtualServerFullFactory + VirtualServerFullFactory, ) @@ -40,11 +35,8 @@ class NetworkableBaseObjectTestMixin(object): """Provides common code required for this test module.""" def _generate_rack_with_networks(self, num_networks=5): - nets = [ - NetworkFactory( - address='10.0.{}.0/24'.format(i) - ) + NetworkFactory(address="10.0.{}.0/24".format(i)) for i in range(num_networks) ] @@ -70,29 +62,31 @@ def setUp(self): self.services = ServiceFactory.create_batch(2) self.service_env = [] for i in range(0, 2): - self.service_env.append(ServiceEnvironment.objects.create( - service=self.services[i], environment=self.envs[i] - )) + self.service_env.append( + ServiceEnvironment.objects.create( + service=self.services[i], environment=self.envs[i] + ) + ) - self.cloud_provider = CloudProviderFactory(name='openstack') + self.cloud_provider = CloudProviderFactory(name="openstack") self.cloud_flavor = CloudFlavorFactory() self.cloud_project = CloudProjectFactory() self.cloud_host = CloudHostFactory(parent=self.cloud_project) self.test_cpu = ComponentModel.objects.create( - name='vcpu1', + name="vcpu1", cores=4, - family='vCPU', + family="vCPU", type=ComponentType.processor, ) self.test_mem = ComponentModel.objects.create( - name='1024 MiB vMEM', - size='1024', + name="1024 MiB vMEM", + size="1024", type=ComponentType.memory, ) self.test_disk = ComponentModel.objects.create( - name='4 GiB vDISK', - size='4096', + name="4 GiB vDISK", + size="4096", type=ComponentType.disk, ) @@ -111,18 +105,18 @@ def setUp(self): @unpack @data( - ('cores', 4), - ('memory', 1024), - ('disk', 4096), + ("cores", 4), + ("memory", 1024), + ("disk", 4096), ) def test_cloudflavor_get_components(self, field, value): self.assertEqual(getattr(self.cloud_flavor, field), value) @unpack @data( - ('cores', 8), - ('memory', 2048), - ('disk', 1024), + ("cores", 8), + ("memory", 2048), + ("disk", 1024), ) def test_cloudflavor_set_components(self, key, value): setattr(self.cloud_flavor, key, value) @@ -130,8 +124,8 @@ def test_cloudflavor_set_components(self, key, value): def test_check_cloudhost_ip_addresses_setter(self): ips_count = IPAddress.objects.count() - ip_addresses = ['10.0.0.1', '10.0.0.2'] - ip_addresses2 = ['10.31.0.1', '10.30.0.0'] + ip_addresses = ["10.0.0.1", "10.0.0.2"] + ip_addresses2 = ["10.31.0.1", "10.30.0.0"] self.cloud_host.ip_addresses = ip_addresses self.assertEqual(set(self.cloud_host.ip_addresses), set(ip_addresses)) self.assertEqual(IPAddress.objects.count(), ips_count + 2) @@ -142,31 +136,27 @@ def test_check_cloudhost_ip_addresses_setter(self): def test_ip_hostname_update(self): ip_addresses = { - '10.0.0.1': 'hostname1.mydc.net', - '10.0.0.2': 'hostname2.mydc.net', + "10.0.0.1": "hostname1.mydc.net", + "10.0.0.2": "hostname2.mydc.net", } ip_addresses2 = { - '10.0.0.1': 'hostname3.mydc.net', - '10.0.0.3': 'hostname4.mydc.net', + "10.0.0.1": "hostname3.mydc.net", + "10.0.0.3": "hostname4.mydc.net", } self.cloud_host.ip_addresses = ip_addresses self.assertEqual(set(self.cloud_host.ip_addresses), set(ip_addresses)) self.assertEqual( - IPAddress.objects.get(address='10.0.0.1').hostname, - 'hostname1.mydc.net' + IPAddress.objects.get(address="10.0.0.1").hostname, "hostname1.mydc.net" ) self.assertEqual( - IPAddress.objects.get(address='10.0.0.2').hostname, - 'hostname2.mydc.net' + IPAddress.objects.get(address="10.0.0.2").hostname, "hostname2.mydc.net" ) self.cloud_host.ip_addresses = ip_addresses2 self.assertEqual( - IPAddress.objects.get(address='10.0.0.1').hostname, - 'hostname3.mydc.net' + IPAddress.objects.get(address="10.0.0.1").hostname, "hostname3.mydc.net" ) self.assertEqual( - IPAddress.objects.get(address='10.0.0.3').hostname, - 'hostname4.mydc.net' + IPAddress.objects.get(address="10.0.0.3").hostname, "hostname4.mydc.net" ) self.assertEqual(set(self.cloud_host.ip_addresses), set(ip_addresses2)) @@ -179,10 +169,7 @@ def test_service_env_inheritance_on_project_change(self): def test_service_env_inheritance_on_host_creation(self): self.cloud_project.service_env = self.service_env[1] self.cloud_project.save() - new_host = CloudHostFactory( - host_id="new_host_id", - parent=self.cloud_project - ) + new_host = CloudHostFactory(host_id="new_host_id", parent=self.cloud_project) self.assertEqual(new_host.service_env, self.service_env[1]) @@ -194,7 +181,7 @@ def setUp(self): self.cloud_host = CloudHostFactory(parent=self.cloud_project) self.custom_field_str = CustomField.objects.create( - name='test str', type=CustomFieldTypes.STRING, default_value='xyz' + name="test str", type=CustomFieldTypes.STRING, default_value="xyz" ) def test_if_custom_fields_are_inherited_from_cloud_project(self): @@ -202,45 +189,37 @@ def test_if_custom_fields_are_inherited_from_cloud_project(self): CustomFieldValue.objects.create( object=self.cloud_project, custom_field=self.custom_field_str, - value='sample_value', + value="sample_value", ) self.assertEqual( - self.cloud_host.custom_fields_as_dict, - {'test str': 'sample_value'} + self.cloud_host.custom_fields_as_dict, {"test str": "sample_value"} ) - def test_if_custom_fields_are_inherited_and_overwrited_from_cloud_project( - self - ): + def test_if_custom_fields_are_inherited_and_overwrited_from_cloud_project(self): self.assertEqual(self.cloud_host.custom_fields_as_dict, {}) CustomFieldValue.objects.create( object=self.cloud_project, custom_field=self.custom_field_str, - value='sample_value', + value="sample_value", ) CustomFieldValue.objects.create( object=self.cloud_host, custom_field=self.custom_field_str, - value='sample_value22', + value="sample_value22", ) self.assertEqual( - self.cloud_host.custom_fields_as_dict, - {'test str': 'sample_value22'} + self.cloud_host.custom_fields_as_dict, {"test str": "sample_value22"} ) def test_get_available_networks(self): rack, nets = self._generate_rack_with_networks() - host = CloudHostFactory( - hypervisor=DataCenterAssetFullFactory(rack=rack) - ) + host = CloudHostFactory(hypervisor=DataCenterAssetFullFactory(rack=rack)) self.assertNetworksTheSame(nets, host._get_available_networks()) def test_cleanup_security_scan_transition(self): - security_scan = SecurityScanFactory( - base_object=self.cloud_host - ) + security_scan = SecurityScanFactory(base_object=self.cloud_host) self.assertEqual(self.cloud_host.securityscan, security_scan) self.assertIsNotNone(self.cloud_host.securityscan.id) CloudHost.cleanup_security_scans((self.cloud_host,)) @@ -251,7 +230,7 @@ class VirtualServerTestCase(RalphTestCase, NetworkableBaseObjectTestMixin): def setUp(self): self.vs = VirtualServerFullFactory(securityscan=None) self.custom_field_str = CustomField.objects.create( - name='test str', type=CustomFieldTypes.STRING, default_value='xyz' + name="test str", type=CustomFieldTypes.STRING, default_value="xyz" ) def test_custom_fields_inheritance_proper_order(self): @@ -261,24 +240,19 @@ def test_custom_fields_inheritance_proper_order(self): CustomFieldValue.objects.create( object=self.vs.configuration_path.module, custom_field=self.custom_field_str, - value='sample_value22', + value="sample_value22", ) CustomFieldValue.objects.create( object=self.vs.configuration_path, custom_field=self.custom_field_str, - value='sample_value', - ) - self.assertEqual( - self.vs.custom_fields_as_dict, - {'test str': 'sample_value'} + value="sample_value", ) + self.assertEqual(self.vs.custom_fields_as_dict, {"test str": "sample_value"}) def test_get_available_networks_dc_asset(self): rack, nets = self._generate_rack_with_networks() - vm = VirtualServerFullFactory( - parent=DataCenterAssetFullFactory(rack=rack) - ) + vm = VirtualServerFullFactory(parent=DataCenterAssetFullFactory(rack=rack)) self.assertNetworksTheSame(nets, vm._get_available_networks()) @@ -286,17 +260,13 @@ def test_get_available_networks_cloud_host(self): rack, nets = self._generate_rack_with_networks() vm = VirtualServerFullFactory( - parent=CloudHostFactory( - hypervisor=DataCenterAssetFullFactory(rack=rack) - ) + parent=CloudHostFactory(hypervisor=DataCenterAssetFullFactory(rack=rack)) ) self.assertNetworksTheSame(nets, vm._get_available_networks()) def test_cleanup_security_scan_transition(self): - security_scan = SecurityScanFactory( - base_object=self.vs - ) + security_scan = SecurityScanFactory(base_object=self.vs) self.assertEqual(self.vs.securityscan, security_scan) self.assertIsNotNone(self.vs.securityscan.id) VirtualServer.cleanup_security_scans((self.vs,)) diff --git a/src/ralph/virtual/tests/test_openstack_sync.py b/src/ralph/virtual/tests/test_openstack_sync.py index 054dd9c019..e21eccfb09 100644 --- a/src/ralph/virtual/tests/test_openstack_sync.py +++ b/src/ralph/virtual/tests/test_openstack_sync.py @@ -18,62 +18,57 @@ CloudHost, CloudProject, CloudProvider, - VirtualComponent + VirtualComponent, ) from ralph.virtual.tests.factories import ( CloudFlavorFactory, CloudHostFactory, CloudHostFullFactory, CloudProjectFactory, - CloudProviderFactory + CloudProviderFactory, ) from ralph.virtual.tests.samples.openstack_data import ( OPENSTACK_DATA, OPENSTACK_FLAVORS, - OPENSTACK_INSTANCES + OPENSTACK_INSTANCES, ) class FakeIronicNode(object): def __init__(self, serial_number, instance_uuid): - self.extra = {'serial_number': serial_number} + self.extra = {"serial_number": serial_number} self.instance_uuid = instance_uuid class TestOpenstackSync(RalphTestCase): - def setUp(self): asset_model = DataCenterAssetModelFactory() - self.cloud_provider = CloudProviderFactory(name='openstack') + self.cloud_provider = CloudProviderFactory(name="openstack") self.cloud_flavor = CloudFlavorFactory.create_batch(3) - self.test_model = ComponentModel(name='delete_test') - VirtualComponent( - model=self.test_model, - base_object=self.cloud_flavor[0] - ) + self.test_model = ComponentModel(name="delete_test") + VirtualComponent(model=self.test_model, base_object=self.cloud_flavor[0]) - self.cloud_project_1 = CloudProjectFactory(project_id='project_id1') - self.cloud_project_2 = CloudProjectFactory(project_id='project_id2') - self.cloud_project_3 = CloudProjectFactory(project_id='project_os_id1') + self.cloud_project_1 = CloudProjectFactory(project_id="project_id1") + self.cloud_project_2 = CloudProjectFactory(project_id="project_id2") + self.cloud_project_3 = CloudProjectFactory(project_id="project_os_id1") self.host = CloudHostFactory( - host_id='host_id1', + host_id="host_id1", parent=self.cloud_project_1, - cloudflavor=self.cloud_flavor[1] + cloudflavor=self.cloud_flavor[1], ) - IPAddress.objects.create(base_object=self.host, address='2.2.3.4') - IPAddress.objects.create(base_object=self.host, address='1.2.3.4') + IPAddress.objects.create(base_object=self.host, address="2.2.3.4") + IPAddress.objects.create(base_object=self.host, address="1.2.3.4") DataCenterAsset.objects.create( - hostname='hypervisor_os1.dcn.net', + hostname="hypervisor_os1.dcn.net", model=asset_model, ) - self.ironic_serial_number_param = 'serial_number' - self.ralph_serial_number_param = 'sn' + self.ironic_serial_number_param = "serial_number" + self.ralph_serial_number_param = "sn" self.ralph_client = RalphClient( - 'openstack', self.ironic_serial_number_param, - self.ralph_serial_number_param + "openstack", self.ironic_serial_number_param, self.ralph_serial_number_param ) self.openstack_client = RalphOpenStackInfrastructureClient( self.cloud_provider.name @@ -83,8 +78,10 @@ def test_check_get_ralph_data(self): ralph_projects = self.ralph_client.get_ralph_servers_data( self.ralph_client.get_ralph_projects() ) - self.assertEqual(ralph_projects['project_id1']['name'], self.cloud_project_1.name) - self.assertIn('host_id1', ralph_projects['project_id1']['servers'].keys()) + self.assertEqual( + ralph_projects["project_id1"]["name"], self.cloud_project_1.name + ) + self.assertIn("host_id1", ralph_projects["project_id1"]["servers"].keys()) def test_check_process_servers(self): """Check if servers are added and modified correctly""" @@ -95,27 +92,25 @@ def test_check_process_servers(self): OPENSTACK_INSTANCES, self.cloud_project_1.project_id, ralph_projects ) for host_id, test_host in OPENSTACK_INSTANCES.items(): - if test_host['status'] == 'DELETED': + if test_host["status"] == "DELETED": self.assertRaises( - ObjectDoesNotExist, CloudHost.objects.get, - host_id=host_id + ObjectDoesNotExist, CloudHost.objects.get, host_id=host_id ) continue host = CloudHost.objects.get(host_id=host_id) ips = host.ip_addresses - self.assertEqual(host.hostname, test_host['hostname']) - self.assertIn(test_host['tag'], host.tags.names()) + self.assertEqual(host.hostname, test_host["hostname"]) + self.assertIn(test_host["tag"], host.tags.names()) self.assertEqual(self.cloud_provider, host.cloudprovider) - for ip in test_host['ips']: + for ip in test_host["ips"]: self.assertIn(ip, list(ips)) - self.assertEqual(host.hypervisor.hostname, test_host['hypervisor']) + self.assertEqual(host.hypervisor.hostname, test_host["hypervisor"]) # check the creation date only for new hosts - if host_id.find('_os_') != -1: + if host_id.find("_os_") != -1: self.assertEqual( datetime.strptime( - test_host['created'], - self.ralph_client.DATETIME_FORMAT + test_host["created"], self.ralph_client.DATETIME_FORMAT ), host.created, ) @@ -124,16 +119,14 @@ def test_check_add_flavor(self): """Check if flavors are added and modified correctly""" ralph_flavors = self.ralph_client.get_ralph_flavors() for flavor_id, flavor in OPENSTACK_FLAVORS.items(): - self.ralph_client._add_or_modify_flavours( - flavor, flavor_id, ralph_flavors - ) + self.ralph_client._add_or_modify_flavours(flavor, flavor_id, ralph_flavors) ralph_flavor = CloudFlavor.objects.get(flavor_id=flavor_id) - self.assertEqual(ralph_flavor.name, flavor['name']) + self.assertEqual(ralph_flavor.name, flavor["name"]) self.assertEqual(ralph_flavor.cloudprovider, self.cloud_provider) - self.assertIn(flavor['tag'], ralph_flavor.tags.names()) - self.assertEqual(flavor['cores'], ralph_flavor.cores) - self.assertEqual(flavor['memory'], ralph_flavor.memory) - self.assertEqual(flavor['disk'], ralph_flavor.disk) + self.assertIn(flavor["tag"], ralph_flavor.tags.names()) + self.assertEqual(flavor["cores"], ralph_flavor.cores) + self.assertEqual(flavor["memory"], ralph_flavor.memory) + self.assertEqual(flavor["disk"], ralph_flavor.disk) def test_check_ralph_update(self): ralph_projects = self.ralph_client.get_ralph_servers_data( @@ -141,34 +134,30 @@ def test_check_ralph_update(self): ) ralph_flavours = self.ralph_client.get_ralph_flavors() self.ralph_client.perform_update( - OPENSTACK_DATA, - OPENSTACK_FLAVORS, - ralph_projects, - ralph_flavours + OPENSTACK_DATA, OPENSTACK_FLAVORS, ralph_projects, ralph_flavours ) # Objects addition/modification for flavor_id, flavor in OPENSTACK_FLAVORS.items(): ralph_flavor = CloudFlavor.objects.get(flavor_id=flavor_id) - self.assertEqual(ralph_flavor.name, flavor['name']) + self.assertEqual(ralph_flavor.name, flavor["name"]) self.assertEqual(ralph_flavor.cloudprovider, self.cloud_provider) for project_id, project in OPENSTACK_DATA.items(): ralph_project = CloudProject.objects.get(project_id=project_id) - self.assertEqual(project['name'], ralph_project.name) + self.assertEqual(project["name"], ralph_project.name) self.assertEqual(self.cloud_provider, ralph_project.cloudprovider) - for host_id, host in OPENSTACK_DATA[project_id]['servers'].items(): - if host['status'] == 'DELETED': + for host_id, host in OPENSTACK_DATA[project_id]["servers"].items(): + if host["status"] == "DELETED": self.assertRaises( - ObjectDoesNotExist, CloudHost.objects.get, - host_id=host_id + ObjectDoesNotExist, CloudHost.objects.get, host_id=host_id ) continue ralph_host = CloudHost.objects.get(host_id=host_id) ips = ralph_host.ip_addresses - self.assertEqual(ralph_host.hostname, host['hostname']) - self.assertIn(host['tag'], ralph_host.tags.names()) - self.assertEqual(set(host['ips']), set(ips)) + self.assertEqual(ralph_host.hostname, host["hostname"]) + self.assertIn(host["tag"], ralph_host.tags.names()) + self.assertEqual(set(host["ips"]), set(ips)) def test_check_ralph_delete(self): ralph_projects = self.ralph_client.get_ralph_servers_data( @@ -176,14 +165,18 @@ def test_check_ralph_delete(self): ) ralph_flavors = self.ralph_client.get_ralph_flavors() servers_to_delete = self.ralph_client.calculate_servers_to_delete( - OPENSTACK_DATA, ralph_projects, + OPENSTACK_DATA, + ralph_projects, ) self.ralph_client.perform_delete( - OPENSTACK_DATA, OPENSTACK_FLAVORS, ralph_projects, ralph_flavors, - servers_to_delete + OPENSTACK_DATA, + OPENSTACK_FLAVORS, + ralph_projects, + ralph_flavors, + servers_to_delete, ) # projects removal - for project_id in ['project_id2', 'project_id3']: + for project_id in ["project_id2", "project_id3"]: self.assertRaises( ObjectDoesNotExist, CloudProject.objects.get, @@ -192,20 +185,20 @@ def test_check_ralph_delete(self): self.assertRaises( ObjectDoesNotExist, CloudFlavor.objects.get, - flavor_id='flavor_id2', + flavor_id="flavor_id2", ) self.assertRaises( ObjectDoesNotExist, CloudHost.objects.get, - host_id='host_id1', + host_id="host_id1", ) def test_check_ralph_delete_incremental(self): # Create server to be deleted in Ralph host_to_delete = CloudHostFactory( - host_id='deleted', + host_id="deleted", parent=self.cloud_project_3, - cloudflavor=self.cloud_flavor[1] + cloudflavor=self.cloud_flavor[1], ) ralph_projects = self.ralph_client.get_ralph_servers_data( self.ralph_client.get_ralph_projects() @@ -215,13 +208,14 @@ def test_check_ralph_delete_incremental(self): OPENSTACK_DATA, ralph_projects, incremental=True ) self.ralph_client.perform_delete( - OPENSTACK_DATA, OPENSTACK_FLAVORS, ralph_projects, ralph_flavors, - servers_to_delete + OPENSTACK_DATA, + OPENSTACK_FLAVORS, + ralph_projects, + ralph_flavors, + servers_to_delete, ) self.assertRaises( - ObjectDoesNotExist, - CloudHost.objects.get, - host_id=host_to_delete.host_id + ObjectDoesNotExist, CloudHost.objects.get, host_id=host_to_delete.host_id ) try: CloudHost.objects.get(host_id=self.host.host_id) @@ -229,57 +223,60 @@ def test_check_ralph_delete_incremental(self): self.fail("Removed host that should have been kept.") def test_cleanup_doesnt_remove_cloud_projects_with_children(self): - project = CloudProjectFactory(project_id='im_not_here') + project = CloudProjectFactory(project_id="im_not_here") CloudHostFactory( - host_id='host_id123', - parent=project, - cloudflavor=self.cloud_flavor[1] + host_id="host_id123", parent=project, cloudflavor=self.cloud_flavor[1] ) ralph_projects = self.ralph_client.get_ralph_servers_data( self.ralph_client.get_ralph_projects() ) ralph_flavors = self.ralph_client.get_ralph_flavors() servers_to_delete = self.ralph_client.calculate_servers_to_delete( - OPENSTACK_DATA, ralph_projects, + OPENSTACK_DATA, + ralph_projects, ) self.ralph_client.perform_delete( - OPENSTACK_DATA, OPENSTACK_FLAVORS, ralph_projects, ralph_flavors, - servers_to_delete + OPENSTACK_DATA, + OPENSTACK_FLAVORS, + ralph_projects, + ralph_flavors, + servers_to_delete, ) try: - CloudProject.objects.get(project_id='im_not_here') + CloudProject.objects.get(project_id="im_not_here") except ObjectDoesNotExist: self.fail('Project "im_not_here" was deleted.') def test_cleanup_doesnt_remove_cloud_projects_with_different_provider(self): CloudProjectFactory( - project_id='im_not_here', - cloudprovider=CloudProviderFactory(name='some_random_provider') + project_id="im_not_here", + cloudprovider=CloudProviderFactory(name="some_random_provider"), ) ralph_projects = self.ralph_client.get_ralph_servers_data( self.ralph_client.get_ralph_projects() ) ralph_flavors = self.ralph_client.get_ralph_flavors() servers_to_delete = self.ralph_client.calculate_servers_to_delete( - OPENSTACK_DATA, ralph_projects, + OPENSTACK_DATA, + ralph_projects, ) self.ralph_client.perform_delete( - OPENSTACK_DATA, OPENSTACK_FLAVORS, ralph_projects, ralph_flavors, - servers_to_delete + OPENSTACK_DATA, + OPENSTACK_FLAVORS, + ralph_projects, + ralph_flavors, + servers_to_delete, ) try: - CloudProject.objects.get(project_id='im_not_here') + CloudProject.objects.get(project_id="im_not_here") except ObjectDoesNotExist: self.fail('Project "im_not_here" was deleted.') def test_cleanup_doesnt_remove_cloud_flavours_with_assignments(self): - flavor = CloudFlavorFactory(flavor_id='im_not_here', name='im_not_here') - CloudHostFactory( - host_id='host_id123', - cloudflavor=flavor - ) + flavor = CloudFlavorFactory(flavor_id="im_not_here", name="im_not_here") + CloudHostFactory(host_id="host_id123", cloudflavor=flavor) openstack_flavors = copy(OPENSTACK_FLAVORS) openstack_flavors.update({flavor.flavor_id: {"name": flavor.name}}) ralph_projects = self.ralph_client.get_ralph_servers_data( @@ -290,12 +287,15 @@ def test_cleanup_doesnt_remove_cloud_flavours_with_assignments(self): OPENSTACK_DATA, ralph_projects, incremental=True ) self.ralph_client.perform_delete( - OPENSTACK_DATA, OPENSTACK_FLAVORS, ralph_projects, ralph_flavors, - servers_to_delete + OPENSTACK_DATA, + OPENSTACK_FLAVORS, + ralph_projects, + ralph_flavors, + servers_to_delete, ) try: - CloudFlavor.objects.get(flavor_id='im_not_here') + CloudFlavor.objects.get(flavor_id="im_not_here") except ObjectDoesNotExist: self.fail('Flavor "im_not_here" was deleted.') @@ -305,69 +305,71 @@ def test_delete_cloud_instance_cleanup_ip(self): self.ralph_client.get_ralph_projects() ) servers_to_delete = self.ralph_client.calculate_servers_to_delete( - OPENSTACK_DATA, ralph_projects, + OPENSTACK_DATA, + ralph_projects, ) self.ralph_client._delete_servers(servers_to_delete) # cloud instance in cloud_project had 2 ip addresses self.assertEqual(IPAddress.objects.count(), ips_count - 2) - @override_settings(OPENSTACK_INSTANCES=[ - { - 'username': 'root', - 'password': 'root', - 'tenant_name': 'admin', - 'version': '2.0', - 'auth_url': 'http://10.20.30.41:1111/v2.0/', - 'tag': 'my_os', - 'network_regex': '.*', - }, - { - 'username': 'root', - 'password': 'root', - 'tenant_name': 'admin2', - 'version': '2.0', - 'auth_url': 'http://10.20.30.42:1111/v2.0/', - 'tag': 'my_os_2', - 'network_regex': '.*', - 'provider': 'openstack', - }, - { - 'username': 'root', - 'password': 'root', - 'tenant_name': 'admin3', - 'version': '2.0', - 'auth_url': 'http://10.20.30.43:1111/v2.0/', - 'tag': 'my_os_3', - 'network_regex': '.*', - 'provider': 'my-own-openstack' - }, - ]) - @mock.patch( - "ralph.lib.openstack.client.RalphOpenstackClient._get_nova_client_connection" + @override_settings( + OPENSTACK_INSTANCES=[ + { + "username": "root", + "password": "root", + "tenant_name": "admin", + "version": "2.0", + "auth_url": "http://10.20.30.41:1111/v2.0/", + "tag": "my_os", + "network_regex": ".*", + }, + { + "username": "root", + "password": "root", + "tenant_name": "admin2", + "version": "2.0", + "auth_url": "http://10.20.30.42:1111/v2.0/", + "tag": "my_os_2", + "network_regex": ".*", + "provider": "openstack", + }, + { + "username": "root", + "password": "root", + "tenant_name": "admin3", + "version": "2.0", + "auth_url": "http://10.20.30.43:1111/v2.0/", + "tag": "my_os_3", + "network_regex": ".*", + "provider": "my-own-openstack", + }, + ] ) @mock.patch( - "ralph.lib.openstack.client.RalphOpenstackClient._get_keystone_client" + "ralph.lib.openstack.client.RalphOpenstackClient._get_nova_client_connection" ) + @mock.patch("ralph.lib.openstack.client.RalphOpenstackClient._get_keystone_client") def test_non_default_provider(self, get_kc, get_nc): tenants = [ - os.site['tenant_name'] for os in self.openstack_client._get_instances_from_settings() + os.site["tenant_name"] + for os in self.openstack_client._get_instances_from_settings() ] - self.assertCountEqual(tenants, ['admin', 'admin2']) + self.assertCountEqual(tenants, ["admin", "admin2"]) RalphClient( - 'my-own-openstack', self.ironic_serial_number_param, - self.ralph_serial_number_param + "my-own-openstack", + self.ironic_serial_number_param, + self.ralph_serial_number_param, ) new_openstack_client = RalphOpenStackInfrastructureClient( - 'my-own-openstack', - ) - self.assertTrue( - CloudProvider.objects.filter(name='my-own-openstack').exists() + "my-own-openstack", ) + self.assertTrue(CloudProvider.objects.filter(name="my-own-openstack").exists()) tenants = [ - os.site['tenant_name'] for os in new_openstack_client._get_instances_from_settings() + os.site["tenant_name"] + for os in new_openstack_client._get_instances_from_settings() ] - self.assertCountEqual(tenants, ['admin3']) + self.assertCountEqual(tenants, ["admin3"]) def test_match_cloud_hosts_all_matched(self): asset_model = DataCenterAssetModelFactory() @@ -375,14 +377,12 @@ def test_match_cloud_hosts_all_matched(self): assets = [ DataCenterAsset.objects.create( - hostname='hostname-{}'.format(i), - model=asset_model, - sn='SN{}'.format(i) + hostname="hostname-{}".format(i), model=asset_model, sn="SN{}".format(i) ) for i in range(num_assets) ] hosts = [ - CloudHostFactory(host_id='fake-instance-uuid-{}'.format(i)) + CloudHostFactory(host_id="fake-instance-uuid-{}".format(i)) for i in range(num_assets) ] @@ -393,9 +393,7 @@ def test_match_cloud_hosts_all_matched(self): self.ralph_client._match_nodes_to_hosts(nodes) - updated_hosts = CloudHost.objects.filter( - id__in=[host.id for host in hosts] - ) + updated_hosts = CloudHost.objects.filter(id__in=[host.id for host in hosts]) for host in updated_hosts: self.assertIsNotNone(host.hypervisor) @@ -410,29 +408,26 @@ def test_match_cloud_hosts_all_matched(self): def test_match_cloud_hosts_ignore_already_matched(self): unassigned_hypervisor = DataCenterAsset.objects.create( - hostname='hypervisor', + hostname="hypervisor", model=DataCenterAssetModelFactory(), - sn='hypervisor-SN' + sn="hypervisor-SN", ) - with_hypervisor = CloudHostFullFactory(host_id='with hypervisor') + with_hypervisor = CloudHostFullFactory(host_id="with hypervisor") with_hypervisor_modified = with_hypervisor.modified with_hypervisor_node = FakeIronicNode( serial_number=with_hypervisor.hypervisor.sn, - instance_uuid=with_hypervisor.host_id + instance_uuid=with_hypervisor.host_id, ) - without_hypervisor = CloudHostFactory(host_id='no hypervisor') + without_hypervisor = CloudHostFactory(host_id="no hypervisor") without_hypervisor_modified = without_hypervisor.modified without_hypervisor_node = FakeIronicNode( serial_number=unassigned_hypervisor.sn, - instance_uuid=without_hypervisor.host_id + instance_uuid=without_hypervisor.host_id, ) - nodes = [ - with_hypervisor_node, - without_hypervisor_node - ] + nodes = [with_hypervisor_node, without_hypervisor_node] self.ralph_client._match_nodes_to_hosts(nodes) without_hypervisor.refresh_from_db() @@ -444,8 +439,8 @@ def test_match_cloud_hosts_ignore_already_matched(self): self.assertTrue(without_hypervisor_modified < without_hypervisor.modified) def test_match_cloud_hosts_host_not_found(self): - host = CloudHostFactory(host_id='foo') - node = FakeIronicNode(serial_number='SN0', instance_uuid='bar') + host = CloudHostFactory(host_id="foo") + node = FakeIronicNode(serial_number="SN0", instance_uuid="bar") self.ralph_client._match_nodes_to_hosts([node]) updated_host = CloudHost.objects.get(pk=host.pk) @@ -454,13 +449,11 @@ def test_match_cloud_hosts_host_not_found(self): def test_match_cloud_hosts_asset_not_found(self): asset_model = DataCenterAssetModelFactory() DataCenterAsset.objects.create( - hostname='hostname-1', - model=asset_model, - sn='FOO' + hostname="hostname-1", model=asset_model, sn="FOO" ) - host = CloudHostFactory(host_id='buz') - node = FakeIronicNode(serial_number='BAR', instance_uuid=host.host_id) + host = CloudHostFactory(host_id="buz") + node = FakeIronicNode(serial_number="BAR", instance_uuid=host.host_id) self.ralph_client._match_nodes_to_hosts([node]) updated_host = CloudHost.objects.get(pk=host.pk) @@ -470,18 +463,13 @@ def test_match_cloud_hosts_asset_duplicate_sn(self): asset_model = DataCenterAssetModelFactory() assets = [ DataCenterAsset.objects.create( - hostname='hostname-{}'.format(i), - model=asset_model, - sn=None + hostname="hostname-{}".format(i), model=asset_model, sn=None ) for i in range(2) ] - host = CloudHostFactory(host_id='bar') - node = FakeIronicNode( - serial_number=assets[0].sn, - instance_uuid=host.host_id - ) + host = CloudHostFactory(host_id="bar") + node = FakeIronicNode(serial_number=assets[0].sn, instance_uuid=host.host_id) self.ralph_client._match_nodes_to_hosts([node]) @@ -489,39 +477,39 @@ def test_match_cloud_hosts_asset_duplicate_sn(self): self.assertIsNone(updated_host.hypervisor) def test_get_or_create_cloud_provider(self): - existing_provider = self.ralph_client._get_or_create_cloud_provider( - 'openstack' - ) + existing_provider = self.ralph_client._get_or_create_cloud_provider("openstack") self.assertEqual(self.cloud_provider.name, existing_provider.name) - new_provider = self.ralph_client._get_or_create_cloud_provider( - 'new_provider' - ) - self.assertEqual( - 'new_provider', new_provider.name - ) + new_provider = self.ralph_client._get_or_create_cloud_provider("new_provider") + self.assertEqual("new_provider", new_provider.name) self.assertIsInstance(new_provider, CloudProvider) def test_get_ralph_projects(self): ralph_projects = self.ralph_client.get_ralph_projects() expected_result = { self.cloud_project_1.project_id: { - 'name': self.cloud_project_1.name, 'servers': {}, 'tags': [] + "name": self.cloud_project_1.name, + "servers": {}, + "tags": [], }, self.cloud_project_2.project_id: { - 'name': self.cloud_project_2.name, 'servers': {}, 'tags': [] + "name": self.cloud_project_2.name, + "servers": {}, + "tags": [], }, self.cloud_project_3.project_id: { - 'name': self.cloud_project_3.name, 'servers': {}, 'tags': [] - } + "name": self.cloud_project_3.name, + "servers": {}, + "tags": [], + }, } self.assertDictEqual(expected_result, ralph_projects) def test_get_ralph_flavors(self): ralph_flavors = self.ralph_client.get_ralph_flavors() expected_flavors = { - self.cloud_flavor[0].flavor_id: {'name': self.cloud_flavor[0].name}, - self.cloud_flavor[1].flavor_id: {'name': self.cloud_flavor[1].name}, - self.cloud_flavor[2].flavor_id: {'name': self.cloud_flavor[2].name} + self.cloud_flavor[0].flavor_id: {"name": self.cloud_flavor[0].name}, + self.cloud_flavor[1].flavor_id: {"name": self.cloud_flavor[1].name}, + self.cloud_flavor[2].flavor_id: {"name": self.cloud_flavor[2].name}, } self.assertEqual(expected_flavors, ralph_flavors) @@ -532,5 +520,7 @@ def test_get_ralph_servers_data(self): ) self.assertIn( self.host.host_id, - ralph_projects_with_servers[self.cloud_project_1.project_id]['servers'].keys() + ralph_projects_with_servers[self.cloud_project_1.project_id][ + "servers" + ].keys(), ) diff --git a/src/ralph/virtual/urls.py b/src/ralph/virtual/urls.py index 96404e70d3..8d4bf5cfa3 100644 --- a/src/ralph/virtual/urls.py +++ b/src/ralph/virtual/urls.py @@ -4,8 +4,8 @@ urlpatterns = [ url( - r'^cloudsync/(?P\d+)/$', + r"^cloudsync/(?P\d+)/$", cloud_sync_router, - name='cloud-sync-router', + name="cloud-sync-router", ), ] From 301ba4866263b1ccb41dfd7acedafe7f6b615e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Szulc?= Date: Fri, 6 Dec 2024 15:54:42 +0100 Subject: [PATCH 08/11] Up Markdown to 3.0 - seems to be working fine --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 2cf5a33e47..d290acdc10 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -2,7 +2,7 @@ -r hermes.txt Django==2.2.28 Faker==0.9.0 -Markdown<3.0 # headerid extension removed in 3.0 - see #3313 for details +Markdown==3.0 Pillow==6.2.2 Unidecode==0.04.18 dj.choices==0.11.0 From 25a9abe61cf4dc39f970c52c213422c2d08dab54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Szulc?= Date: Fri, 6 Dec 2024 16:08:26 +0100 Subject: [PATCH 09/11] Add ruff to reqs Fix imports with ruff --- contrib/dhcp_agent/dhcp_agent.py | 9 +++---- contrib/dhcp_agent/test.py | 8 +++---- docker/provision/createsuperuser.py | 1 - requirements/code_style.txt | 1 + setup.py | 5 ++-- .../access_cards/migrations/0001_initial.py | 5 ++-- .../migrations/0002_auto_20200116_1248.py | 3 ++- .../migrations/0003_auto_20200121_1354.py | 1 + .../migrations/0004_auto_20200513_1014.py | 1 + .../accessories/migrations/0001_initial.py | 7 +++--- .../migrations/0002_auto_20210510_1246.py | 4 ++-- src/ralph/accessories/models.py | 1 - src/ralph/accessories/tests/factories.py | 2 +- src/ralph/accounts/ldap.py | 2 +- src/ralph/accounts/ldap_helpers.py | 1 - src/ralph/accounts/migrations/0001_initial.py | 5 ++-- src/ralph/accounts/views.py | 2 +- src/ralph/admin/decorators.py | 2 +- src/ralph/admin/m2m.py | 2 +- src/ralph/admin/sitetrees.py | 2 +- src/ralph/admin/tests/tests_filters.py | 2 +- src/ralph/admin/views/extra.py | 4 ++-- src/ralph/admin/views/main.py | 2 +- src/ralph/api/__init__.py | 2 +- src/ralph/api/permissions.py | 2 +- src/ralph/api/serializers.py | 2 +- src/ralph/api/tests/_base.py | 2 +- src/ralph/api/tests/test_filters.py | 4 ++-- src/ralph/assets/apps.py | 1 + src/ralph/assets/migrations/0001_initial.py | 11 +++++---- .../migrations/0008_auto_20160122_1429.py | 2 +- .../migrations/0009_auto_20160307_1138.py | 1 + .../migrations/0011_auto_20160603_0742.py | 1 + .../migrations/0012_auto_20160606_1409.py | 14 ++++++----- src/ralph/assets/migrations/0014_memory.py | 2 +- .../migrations/0015_auto_20160701_0952.py | 1 + .../migrations/0016_fibrechannelcard.py | 3 ++- src/ralph/assets/migrations/0017_processor.py | 2 +- src/ralph/assets/migrations/0018_disk.py | 2 +- .../migrations/0019_auto_20160719_1443.py | 6 +++-- .../migrations/0022_auto_20160823_0921.py | 1 + .../migrations/0024_auto_20170322_1148.py | 2 +- .../migrations/0025_auto_20170331_1341.py | 2 +- .../migrations/0026_auto_20170510_0840.py | 3 ++- .../migrations/0031_auto_20200728_1326.py | 2 +- .../migrations/0032_auto_20200909_1012.py | 5 ++-- .../migrations/0033_auto_20211115_1125.py | 1 + .../migrations/0035_auto_20240506_1633.py | 2 +- .../migrations/0036_auto_20240904_1126.py | 1 + .../migrations/0037_auto_20240621_1217.py | 2 +- src/ralph/assets/models/__init__.py | 8 +++---- src/ralph/assets/subscribers.py | 1 - src/ralph/assets/tests/test_api.py | 2 +- .../attachments/migrations/0001_initial.py | 3 ++- .../migrations/0003_auto_20160121_1346.py | 1 + src/ralph/attachments/tests/__init__.py | 3 +-- .../back_office/migrations/0001_initial.py | 7 +++--- .../migrations/0007_auto_20180105_0910.py | 1 + .../migrations/0008_auto_20180801_1157.py | 1 + .../migrations/0009_auto_20181016_1252.py | 1 + .../migrations/0010_backofficeasset_imei2.py | 1 + .../migrations/0011_auto_20190517_1115.py | 1 + .../migrations/0012_auto_20210318_1230.py | 1 + .../migrations/0013_auto_20220421_1202.py | 1 + .../migrations/0014_auto_20221108_1007.py | 1 + .../migrations/0015_auto_20221207_1445.py | 1 + .../migrations/0016_auto_20221220_1210.py | 1 + .../migrations/0017_auto_20230112_0949.py | 1 + .../migrations/0018_auto_20230206_1020.py | 1 + .../migrations/0020_auto_20230419_1223.py | 3 ++- .../migrations/0021_auto_20230511_1202.py | 1 + .../migrations/0022_auto_20230616_1235.py | 1 + .../migrations/0023_auto_20240223_1018.py | 1 + .../migrations/0024_auto_20240621_1217.py | 2 +- src/ralph/back_office/tests/test_models.py | 8 +++---- .../migrations/0002_auto_20170622_1254.py | 3 ++- src/ralph/configuration_management/views.py | 1 - src/ralph/dashboards/api/views.py | 1 + .../dashboards/migrations/0001_initial.py | 2 +- .../migrations/0007_auto_20240723_1148.py | 2 +- src/ralph/data_center/admin.py | 4 ++-- src/ralph/data_center/api/serializers.py | 8 ++++--- src/ralph/data_center/api/views.py | 4 ++-- src/ralph/data_center/apps.py | 1 + .../data_center/migrations/0001_initial.py | 10 ++++---- .../migrations/0003_auto_20151126_2222.py | 1 + .../migrations/0005_auto_20160121_1133.py | 1 + .../migrations/0009_auto_20160419_1003.py | 1 + .../migrations/0011_change_networks_models.py | 5 ++-- .../migrations/0013_auto_20160606_1438.py | 6 +++-- .../migrations/0021_auto_20161003_0751.py | 2 +- .../migrations/0022_auto_20161206_1521.py | 1 + .../migrations/0023_rack_reverse_ordering.py | 2 +- .../migrations/0024_auto_20170331_1341.py | 2 +- .../migrations/0025_auto_20170510_1122.py | 1 + .../migrations/0026_auto_20170614_1237.py | 2 +- .../migrations/0032_auto_20240521_1542.py | 2 +- .../migrations/0033_auto_20240621_1217.py | 3 ++- .../migrations/0034_auto_20240628_1207.py | 3 ++- src/ralph/data_center/models/__init__.py | 2 +- src/ralph/data_center/models/physical.py | 2 +- src/ralph/data_center/publishers.py | 6 +++-- src/ralph/data_center/subscribers.py | 2 +- src/ralph/data_center/tests/factories.py | 4 ++-- src/ralph/data_center/tests/test_admin.py | 2 +- src/ralph/data_center/tests/test_api.py | 1 - src/ralph/data_center/tests/test_models.py | 2 +- .../data_center/tests/test_subscribers.py | 2 +- .../commands/create_server_model.py | 1 - .../management/commands/initial_data.py | 2 +- src/ralph/data_importer/resources.py | 2 +- src/ralph/deployment/deployment.py | 2 +- .../deployment/migrations/0001_initial.py | 1 + .../migrations/0005_auto_20180625_1257.py | 1 + .../migrations/0007_auto_20240506_1633.py | 2 +- .../migrations/0009_auto_20240924_1133.py | 1 + src/ralph/deployment/tests/test_deployment.py | 2 +- src/ralph/deployment/views.py | 1 + .../migrations/0004_add_dns_server_group.py | 1 + src/ralph/dhcp/tests/test_agent.py | 3 +-- src/ralph/dns/apps.py | 1 + src/ralph/dns/dnsaas.py | 1 + src/ralph/dns/tests.py | 4 ++-- src/ralph/domains/apps.py | 1 + src/ralph/domains/migrations/0001_initial.py | 3 ++- .../migrations/0005_auto_20170523_1214.py | 1 + .../migrations/0006_auto_20180725_1216.py | 1 + .../migrations/0007_auto_20200909_1012.py | 5 ++-- .../migrations/0008_auto_20240621_1011.py | 2 +- src/ralph/domains/publishers.py | 1 - src/ralph/helpers.py | 2 +- src/ralph/lib/api/exception_handler.py | 1 - src/ralph/lib/cache/__init__.py | 1 - src/ralph/lib/custom_fields/admin.py | 2 +- src/ralph/lib/custom_fields/api/routers.py | 3 ++- .../lib/custom_fields/api/serializers.py | 2 +- src/ralph/lib/custom_fields/api/viewsets.py | 5 +--- src/ralph/lib/custom_fields/fields.py | 2 +- src/ralph/lib/custom_fields/forms.py | 2 +- .../custom_fields/migrations/0001_initial.py | 2 +- src/ralph/lib/custom_fields/models.py | 9 +++---- src/ralph/lib/custom_fields/signals.py | 1 - src/ralph/lib/custom_fields/tests/api.py | 2 +- .../lib/custom_fields/tests/factories.py | 2 +- src/ralph/lib/custom_fields/tests/test_api.py | 1 + src/ralph/lib/external_services/__init__.py | 1 - .../migrations/0001_initial.py | 6 +++-- src/ralph/lib/hooks/__init__.py | 1 - src/ralph/lib/metrics/__init__.py | 2 +- src/ralph/lib/metrics/collector.py | 2 +- src/ralph/lib/metrics/middlewares.py | 3 ++- src/ralph/lib/mixins/fields.py | 1 - .../mixins/tests/migrations/0001_initial.py | 1 + src/ralph/lib/mixins/tests/test_api.py | 2 +- src/ralph/lib/openstack/client.py | 4 ++-- src/ralph/lib/permissions/admin.py | 5 +--- src/ralph/lib/permissions/api.py | 5 +--- src/ralph/lib/permissions/tests/api.py | 9 ++----- .../tests/migrations/0001_initial.py | 2 +- src/ralph/lib/permissions/tests/models.py | 2 +- .../tests/test_permissions_per_object.py | 4 ++-- .../migrations/0003_auto_20240506_1133.py | 2 +- .../migrations/0004_auto_20240924_1142.py | 1 + .../lib/polymorphic/tests/tests_models.py | 2 +- src/ralph/lib/serializers/__init__.py | 5 ++-- src/ralph/lib/table/table.py | 2 +- src/ralph/lib/threadlocal/middleware.py | 3 +-- src/ralph/lib/transitions/admin.py | 6 +---- src/ralph/lib/transitions/api/routers.py | 2 +- src/ralph/lib/transitions/api/serializers.py | 2 +- src/ralph/lib/transitions/api/views.py | 14 +++++------ src/ralph/lib/transitions/async.py | 8 +++---- src/ralph/lib/transitions/checks.py | 2 +- src/ralph/lib/transitions/conf.py | 1 - src/ralph/lib/transitions/forms.py | 4 ++-- .../transitions/migrations/0001_initial.py | 2 +- .../migrations/0004_auto_20160127_1119.py | 1 + .../migrations/0005_auto_20160606_1420.py | 2 +- .../migrations/0006_auto_20170719_1209.py | 1 + .../migrations/0009_transition_success_url.py | 3 ++- src/ralph/lib/transitions/models.py | 24 +++++-------------- src/ralph/lib/transitions/tests/__init__.py | 1 - src/ralph/lib/transitions/tests/factories.py | 2 +- .../lib/transitions/tests/test_actions.py | 7 ++---- src/ralph/lib/transitions/tests/test_async.py | 4 ++-- .../lib/transitions/tests/test_models.py | 6 ++--- src/ralph/lib/transitions/tests/test_utils.py | 2 +- src/ralph/lib/transitions/urls.py | 2 +- src/ralph/lib/transitions/views.py | 6 ++--- src/ralph/licences/migrations/0001_initial.py | 5 ++-- .../migrations/0002_auto_20151204_1325.py | 1 + .../migrations/0006_auto_20200909_1115.py | 5 ++-- .../migrations/0007_auto_20240506_1633.py | 2 +- .../migrations/0008_auto_20240628_1207.py | 3 ++- src/ralph/licences/models.py | 1 - src/ralph/networks/fields.py | 1 - src/ralph/networks/filters.py | 3 ++- src/ralph/networks/migrations/0001_initial.py | 9 +++---- .../migrations/0004_auto_20160606_1512.py | 6 +++-- .../migrations/0007_auto_20160804_1409.py | 1 + .../migrations/0009_auto_20160823_0921.py | 1 + .../migrations/0010_auto_20170216_1230.py | 2 +- .../migrations/0013_auto_20171006_0947.py | 2 +- .../migrations/0014_auto_20171009_1030.py | 2 +- .../migrations/0015_auto_20211115_1125.py | 1 + .../migrations/0016_auto_20240924_1155.py | 1 + src/ralph/networks/models/networks.py | 2 +- src/ralph/networks/tests/test_models.py | 2 +- src/ralph/operations/changemanagement/jira.py | 1 - .../changemanagement/subscribtions.py | 1 - .../operations/migrations/0001_initial.py | 7 +++--- .../migrations/0003_auto_20160303_1114.py | 1 + .../migrations/0004_auto_20160307_1138.py | 1 + .../migrations/0005_auto_20170323_1425.py | 1 + .../migrations/0007_auto_20170328_1728.py | 2 +- .../migrations/0008_auto_20170331_0952.py | 2 +- .../migrations/0009_auto_20170403_1112.py | 1 + .../migrations/0010_auto_20170410_1031.py | 4 ++-- .../migrations/0011_operation_reporter.py | 4 ++-- .../migrations/0013_auto_20241002_1122.py | 1 + .../commands/send_data_center_asset_export.py | 1 - src/ralph/reports/migrations/0001_initial.py | 1 + src/ralph/security/api.py | 2 +- .../management/commands/update_is_patched.py | 1 - src/ralph/security/migrations/0001_initial.py | 2 +- .../migrations/0002_auto_20160307_1138.py | 1 + src/ralph/security/transitions.py | 1 - src/ralph/settings/base.py | 3 +-- src/ralph/settings/dev.py | 6 ++--- src/ralph/settings/hooks.py | 1 - .../sim_cards/migrations/0001_initial.py | 7 +++--- .../migrations/0002_auto_20181123_1138.py | 1 + .../migrations/0004_simcard_property_of.py | 2 +- src/ralph/sim_cards/models.py | 3 +-- .../commands/import_ssl_certificates.py | 1 - .../migrations/0001_initial.py | 5 ++-- .../migrations/0002_auto_20180522_1244.py | 2 +- .../migrations/0005_auto_20200909_1012.py | 5 ++-- .../migrations/0007_auto_20240621_1217.py | 2 +- src/ralph/supports/migrations/0001_initial.py | 3 ++- .../migrations/0006_auto_20160615_0805.py | 1 + .../migrations/0008_auto_20200909_1012.py | 5 ++-- .../migrations/0009_auto_20240506_1633.py | 2 +- .../migrations/0010_auto_20240628_1207.py | 3 ++- .../migrations/0010_auto_20241002_1122.py | 1 + src/ralph/tests/migrations/0001_initial.py | 3 ++- .../migrations/0002_auto_20160119_0914.py | 1 + .../migrations/0006_auto_20160607_0842.py | 1 + .../migrations/0008_auto_20200909_1322.py | 5 ++-- .../migrations/0009_auto_20240621_1009.py | 2 +- .../migrations/0010_auto_20240621_1217.py | 3 ++- .../migrations/0011_auto_20240621_1231.py | 3 ++- .../migrations/0012_auto_20240621_1355.py | 3 ++- .../migrations/0013_auto_20240627_1512.py | 3 ++- .../migrations/0014_auto_20240628_1213.py | 3 ++- src/ralph/tests/mixins.py | 1 + src/ralph/trade_marks/admin.py | 2 +- .../trade_marks/migrations/0001_initial.py | 3 ++- .../migrations/0003_trademark_image.py | 1 + .../migrations/0004_auto_20190221_0923.py | 1 + .../migrations/0008_auto_20210625_0738.py | 3 ++- .../migrations/0011_trademarkkind.py | 1 + .../migrations/0013_auto_20211206_1400.py | 2 +- .../migrations/0014_auto_20211207_1118.py | 2 +- .../migrations/0015_auto_20221020_1340.py | 5 ++-- .../migrations/0016_auto_20240621_1217.py | 2 +- src/ralph/urls/dev.py | 3 +-- src/ralph/urls/test.py | 5 ++-- src/ralph/virtual/api.py | 2 +- .../management/commands/openstack_sync.py | 2 +- .../migrations/0002_auto_20160226_0826.py | 2 +- .../migrations/0003_auto_20160606_1442.py | 4 +++- .../migrations/0004_virtualserver_status.py | 1 + .../migrations/0007_auto_20160630_0949.py | 1 + .../0011_cloudprovider_client_config.py | 4 ++-- .../virtual/migrations/0012_cloudimage.py | 1 + .../migrations/0014_auto_20240621_1009.py | 2 +- .../migrations/0015_auto_20240621_1217.py | 2 +- src/ralph/virtual/processors/noop.py | 1 - 279 files changed, 411 insertions(+), 345 deletions(-) diff --git a/contrib/dhcp_agent/dhcp_agent.py b/contrib/dhcp_agent/dhcp_agent.py index d6248eb860..f0f425504a 100644 --- a/contrib/dhcp_agent/dhcp_agent.py +++ b/contrib/dhcp_agent/dhcp_agent.py @@ -11,20 +11,21 @@ import subprocess import sys import tempfile -from optparse import OptionParser from logging import handlers as logging_handlers +from optparse import OptionParser IS_PY3 = sys.version_info[0] == 3 if IS_PY3: from dbm import gnu as cache_db - from urllib.request import urlopen, Request - from urllib.parse import urlencode from urllib.error import HTTPError + from urllib.parse import urlencode + from urllib.request import Request, urlopen string_types = (str,) else: import dbm as cache_db from urllib import urlencode - from urllib2 import urlopen, Request, HTTPError + + from urllib2 import HTTPError, Request, urlopen string_types = (basestring,) diff --git a/contrib/dhcp_agent/test.py b/contrib/dhcp_agent/test.py index 307a8ab4ac..b6c9109b4c 100644 --- a/contrib/dhcp_agent/test.py +++ b/contrib/dhcp_agent/test.py @@ -1,14 +1,14 @@ -import unittest import logging -from mock import patch, MagicMock, Mock +import unittest from optparse import Values from dhcp_agent import ( + Cache, + DHCPConfigManager, _check_params, _get_cmd_params_from_parser, - Cache, - DHCPConfigManager ) +from mock import MagicMock, Mock, patch logger = logging.getLogger(__file__) mocked_parser = MagicMock() diff --git a/docker/provision/createsuperuser.py b/docker/provision/createsuperuser.py index a55e423e9c..59d456f2a5 100644 --- a/docker/provision/createsuperuser.py +++ b/docker/provision/createsuperuser.py @@ -7,7 +7,6 @@ from django.contrib.auth import get_user_model - User = get_user_model() username = os.getenv('RALPH_DEFAULT_SUPERUSER_NAME', 'ralph') diff --git a/requirements/code_style.txt b/requirements/code_style.txt index a261921910..7b4f415bf2 100644 --- a/requirements/code_style.txt +++ b/requirements/code_style.txt @@ -1,3 +1,4 @@ flake8==3.7.9 isort==4.2.5 pyflakes==1.5.0 +ruff==0.8.2 diff --git a/setup.py b/setup.py index e2431f2fd1..41672a5040 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,10 @@ # -*- encoding: utf-8 -*- import os -import sys -from setuptools import setup, find_packages import subprocess +import sys + +from setuptools import find_packages, setup assert sys.version_info >= (3, 3), 'Python 3.3+ required.' diff --git a/src/ralph/access_cards/migrations/0001_initial.py b/src/ralph/access_cards/migrations/0001_initial.py index d18a0a2d99..0f718c5bd8 100644 --- a/src/ralph/access_cards/migrations/0001_initial.py +++ b/src/ralph/access_cards/migrations/0001_initial.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import dj.choices.fields -from django.conf import settings import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + import ralph.access_cards.models import ralph.lib.mixins.models diff --git a/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py b/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py index d3c5179de9..b434d077b4 100644 --- a/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py +++ b/src/ralph/access_cards/migrations/0002_auto_20200116_1248.py @@ -2,8 +2,9 @@ from __future__ import unicode_literals import django -from django.db import migrations, models import mptt.fields +from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py b/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py index f37781c373..f56697aaab 100644 --- a/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py +++ b/src/ralph/access_cards/migrations/0003_auto_20200121_1354.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py b/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py index dd90e5aaf3..17378310e5 100644 --- a/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py +++ b/src/ralph/access_cards/migrations/0004_auto_20200513_1014.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/accessories/migrations/0001_initial.py b/src/ralph/accessories/migrations/0001_initial.py index 0cd7ef0652..b349ac11ae 100644 --- a/src/ralph/accessories/migrations/0001_initial.py +++ b/src/ralph/accessories/migrations/0001_initial.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -import ralph.lib.transitions.fields -import ralph.lib.mixins.models import django.db.models.deletion from django.conf import settings +from django.db import migrations, models + +import ralph.lib.mixins.models +import ralph.lib.transitions.fields class Migration(migrations.Migration): diff --git a/src/ralph/accessories/migrations/0002_auto_20210510_1246.py b/src/ralph/accessories/migrations/0002_auto_20210510_1246.py index fd870bd376..f5bbf3b69e 100644 --- a/src/ralph/accessories/migrations/0002_auto_20210510_1246.py +++ b/src/ralph/accessories/migrations/0002_auto_20210510_1246.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -import mptt.fields import django.db.models.deletion +import mptt.fields +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/accessories/models.py b/src/ralph/accessories/models.py index eaa55ce589..b14202acaf 100644 --- a/src/ralph/accessories/models.py +++ b/src/ralph/accessories/models.py @@ -18,7 +18,6 @@ from ralph.lib.transitions.fields import TransitionField from ralph.lib.transitions.models import TransitionWorkflowBaseWithPermissions - _SELECT_USED_ACCESSORY_QUERY = """ SELECT COALESCE(SUM({assignment_table}.{quantity_column}), 0) FROM {assignment_table} diff --git a/src/ralph/accessories/tests/factories.py b/src/ralph/accessories/tests/factories.py index 81fe925c2f..4df6b0e9fc 100644 --- a/src/ralph/accessories/tests/factories.py +++ b/src/ralph/accessories/tests/factories.py @@ -1,4 +1,4 @@ -from factory import post_generation, Sequence, SubFactory +from factory import Sequence, SubFactory, post_generation from factory.django import DjangoModelFactory from ralph.accessories.models import Accessory, AccessoryStatus, AccessoryUser diff --git a/src/ralph/accounts/ldap.py b/src/ralph/accounts/ldap.py index efa9b50f56..74d090d254 100644 --- a/src/ralph/accounts/ldap.py +++ b/src/ralph/accounts/ldap.py @@ -6,7 +6,7 @@ from django.contrib.auth.models import Group from django.dispatch import receiver from django.utils.encoding import force_text -from django_auth_ldap.backend import _LDAPUser, LDAPSettings, populate_user +from django_auth_ldap.backend import LDAPSettings, _LDAPUser, populate_user logger = logging.getLogger(__name__) diff --git a/src/ralph/accounts/ldap_helpers.py b/src/ralph/accounts/ldap_helpers.py index c5fa57a1a3..2865496e2c 100644 --- a/src/ralph/accounts/ldap_helpers.py +++ b/src/ralph/accounts/ldap_helpers.py @@ -5,7 +5,6 @@ from django.utils.encoding import force_text from django_auth_ldap.config import ActiveDirectoryGroupType - logger = logging.getLogger(__name__) diff --git a/src/ralph/accounts/migrations/0001_initial.py b/src/ralph/accounts/migrations/0001_initial.py index d53481599c..1dc095dc27 100644 --- a/src/ralph/accounts/migrations/0001_initial.py +++ b/src/ralph/accounts/migrations/0001_initial.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +import django.contrib.auth.models import django.core.validators import django.utils.timezone +from django.db import migrations, models + import ralph.lib.mixins.models -import django.contrib.auth.models class Migration(migrations.Migration): diff --git a/src/ralph/accounts/views.py b/src/ralph/accounts/views.py index f3b76158aa..e3920f034e 100644 --- a/src/ralph/accounts/views.py +++ b/src/ralph/accounts/views.py @@ -18,8 +18,8 @@ ) from ralph.accounts.helpers import ( ACCEPTANCE_LOAN_TRANSITION_ID, - acceptance_transition_exists, ACCEPTANCE_TRANSITION_ID, + acceptance_transition_exists, get_acceptance_url, get_assets_to_accept, get_assets_to_accept_loan, diff --git a/src/ralph/admin/decorators.py b/src/ralph/admin/decorators.py index 4377a51983..3bde3ca665 100644 --- a/src/ralph/admin/decorators.py +++ b/src/ralph/admin/decorators.py @@ -6,7 +6,7 @@ from django.db.models import Model from ralph.admin.sites import ralph_site -from ralph.admin.views.extra import CHANGE, LIST, RalphExtraViewMixin, VIEW_TYPES +from ralph.admin.views.extra import CHANGE, LIST, VIEW_TYPES, RalphExtraViewMixin register = partial(django_register, site=ralph_site) diff --git a/src/ralph/admin/m2m.py b/src/ralph/admin/m2m.py index e3e52d3015..2b2e4c7c70 100644 --- a/src/ralph/admin/m2m.py +++ b/src/ralph/admin/m2m.py @@ -43,7 +43,7 @@ class AuthorAdmin(admin.ModelAdmin): from functools import partial from django import forms -from django.contrib.admin.utils import flatten_fieldsets, NestedObjects +from django.contrib.admin.utils import NestedObjects, flatten_fieldsets from django.core.exceptions import ValidationError from django.db import router from django.db.models import ForeignKey diff --git a/src/ralph/admin/sitetrees.py b/src/ralph/admin/sitetrees.py index f5b0a0f15c..a3717934c9 100644 --- a/src/ralph/admin/sitetrees.py +++ b/src/ralph/admin/sitetrees.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from django.apps import apps from django.conf import settings -from django.utils.translation import ugettext_lazy as _ from django.utils.translation import activate +from django.utils.translation import ugettext_lazy as _ from sitetree.sitetreeapp import register_i18n_trees from sitetree.utils import item, tree diff --git a/src/ralph/admin/tests/tests_filters.py b/src/ralph/admin/tests/tests_filters.py index cd7b46ff0b..45d37a2207 100644 --- a/src/ralph/admin/tests/tests_filters.py +++ b/src/ralph/admin/tests/tests_filters.py @@ -10,7 +10,6 @@ from ralph.admin.filters import ( BooleanListFilter, ChoicesListFilter, - date_format_to_human, DateListFilter, IPFilter, LiquidatedStatusFilter, @@ -20,6 +19,7 @@ TagsListFilter, TextListFilter, TreeRelatedAutocompleteFilterWithDescendants, + date_format_to_human, ) from ralph.admin.sites import ralph_site from ralph.assets.tests.factories import ( diff --git a/src/ralph/admin/views/extra.py b/src/ralph/admin/views/extra.py index 950980c33c..7675a32030 100644 --- a/src/ralph/admin/views/extra.py +++ b/src/ralph/admin/views/extra.py @@ -6,10 +6,10 @@ from django.shortcuts import get_object_or_404 from ralph.admin.mixins import ( - get_inline_media, - initialize_search_form, RalphAdmin, RalphTemplateView, + get_inline_media, + initialize_search_form, ) from ralph.admin.sites import ralph_site from ralph.helpers import get_model_view_url_name diff --git a/src/ralph/admin/views/main.py b/src/ralph/admin/views/main.py index 5ed30c923e..f38b8abb74 100644 --- a/src/ralph/admin/views/main.py +++ b/src/ralph/admin/views/main.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from django.contrib.admin.views.main import ChangeList, SEARCH_VAR +from django.contrib.admin.views.main import SEARCH_VAR, ChangeList SEARCH_SCOPE_VAR = "search-scope" BULK_EDIT_VAR = "bulk_edit" diff --git a/src/ralph/api/__init__.py b/src/ralph/api/__init__.py index a25eed24a1..024653b9fa 100644 --- a/src/ralph/api/__init__.py +++ b/src/ralph/api/__init__.py @@ -1,6 +1,6 @@ +from ralph.api.routers import router from ralph.api.serializers import RalphAPISerializer from ralph.api.viewsets import RalphAPIViewSet, RalphReadOnlyAPIViewSet -from ralph.api.routers import router __all__ = [ "RalphAPISerializer", diff --git a/src/ralph/api/permissions.py b/src/ralph/api/permissions.py index 754d76690d..789eafdd88 100644 --- a/src/ralph/api/permissions.py +++ b/src/ralph/api/permissions.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from rest_framework.permissions import BasePermission, SAFE_METHODS +from rest_framework.permissions import SAFE_METHODS, BasePermission class IsSuperuserOrReadonly(BasePermission): diff --git a/src/ralph/api/serializers.py b/src/ralph/api/serializers.py index ef74b9bed7..0f68daee98 100644 --- a/src/ralph/api/serializers.py +++ b/src/ralph/api/serializers.py @@ -3,8 +3,8 @@ import operator from functools import reduce -from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import NON_FIELD_ERRORS, ObjectDoesNotExist +from django.core.exceptions import ValidationError as DjangoValidationError from django.db import transaction from django.db.models import Q from django.db.models.fields import exceptions diff --git a/src/ralph/api/tests/_base.py b/src/ralph/api/tests/_base.py index b8cda55bd3..ce3ed19f14 100644 --- a/src/ralph/api/tests/_base.py +++ b/src/ralph/api/tests/_base.py @@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType -from django.db import connections, DEFAULT_DB_ALIAS +from django.db import DEFAULT_DB_ALIAS, connections from django.test.utils import CaptureQueriesContext # noqa from rest_framework.test import APITestCase diff --git a/src/ralph/api/tests/test_filters.py b/src/ralph/api/tests/test_filters.py index 6e9aaa1f16..71b70ce3bd 100644 --- a/src/ralph/api/tests/test_filters.py +++ b/src/ralph/api/tests/test_filters.py @@ -8,10 +8,10 @@ from rest_framework.test import APIClient, APIRequestFactory from ralph.api.filters import ( - ExtendedFiltersBackend, FALSE_VALUES, - LookupFilterBackend, TRUE_VALUES, + ExtendedFiltersBackend, + LookupFilterBackend, ) from ralph.api.tests.api import Bar, BarViewSet, ManufacturerViewSet, TestManufacturer from ralph.tests import RalphTestCase diff --git a/src/ralph/assets/apps.py b/src/ralph/assets/apps.py index 45bf343b42..4185dbffd0 100644 --- a/src/ralph/assets/apps.py +++ b/src/ralph/assets/apps.py @@ -1,4 +1,5 @@ from django.conf import settings + from ralph.apps import RalphAppConfig diff --git a/src/ralph/assets/migrations/0001_initial.py b/src/ralph/assets/migrations/0001_initial.py index 0dfec36bf5..2cbd48ca13 100644 --- a/src/ralph/assets/migrations/0001_initial.py +++ b/src/ralph/assets/migrations/0001_initial.py @@ -1,14 +1,15 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -from django.conf import settings -import django.db.models.deletion -import taggit.managers import django.core.validators +import django.db.models.deletion import mptt.fields -import ralph.lib.mixins.models +import taggit.managers +from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.fields +import ralph.lib.mixins.models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0008_auto_20160122_1429.py b/src/ralph/assets/migrations/0008_auto_20160122_1429.py index 4f59e152ec..7bc8cdd98a 100644 --- a/src/ralph/assets/migrations/0008_auto_20160122_1429.py +++ b/src/ralph/assets/migrations/0008_auto_20160122_1429.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.core.validators +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0009_auto_20160307_1138.py b/src/ralph/assets/migrations/0009_auto_20160307_1138.py index eb98f65e8b..a356458cab 100644 --- a/src/ralph/assets/migrations/0009_auto_20160307_1138.py +++ b/src/ralph/assets/migrations/0009_auto_20160307_1138.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.models diff --git a/src/ralph/assets/migrations/0011_auto_20160603_0742.py b/src/ralph/assets/migrations/0011_auto_20160603_0742.py index 8755530ac9..cbbcd26d82 100644 --- a/src/ralph/assets/migrations/0011_auto_20160603_0742.py +++ b/src/ralph/assets/migrations/0011_auto_20160603_0742.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/assets/migrations/0012_auto_20160606_1409.py b/src/ralph/assets/migrations/0012_auto_20160606_1409.py index 7abd199e0b..e8607491ce 100644 --- a/src/ralph/assets/migrations/0012_auto_20160606_1409.py +++ b/src/ralph/assets/migrations/0012_auto_20160606_1409.py @@ -1,15 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -import ralph.lib.mixins.models -import django.db.models.deletion -import django.core.validators -import ralph.lib.mixins.fields -import mptt.fields import datetime import re +import django.core.validators +import django.db.models.deletion +import mptt.fields +from django.db import migrations, models + +import ralph.lib.mixins.fields +import ralph.lib.mixins.models + class Migration(migrations.Migration): dependencies = [ diff --git a/src/ralph/assets/migrations/0014_memory.py b/src/ralph/assets/migrations/0014_memory.py index 4d39e151a0..fcb7cec630 100644 --- a/src/ralph/assets/migrations/0014_memory.py +++ b/src/ralph/assets/migrations/0014_memory.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0015_auto_20160701_0952.py b/src/ralph/assets/migrations/0015_auto_20160701_0952.py index 06a6de74c2..39c6b4e399 100644 --- a/src/ralph/assets/migrations/0015_auto_20160701_0952.py +++ b/src/ralph/assets/migrations/0015_auto_20160701_0952.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/assets/migrations/0016_fibrechannelcard.py b/src/ralph/assets/migrations/0016_fibrechannelcard.py index fe96d7b954..bc42ec2d78 100644 --- a/src/ralph/assets/migrations/0016_fibrechannelcard.py +++ b/src/ralph/assets/migrations/0016_fibrechannelcard.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import django.db.models.deletion from django.db import migrations, models + import ralph.lib.mixins.fields -import django.db.models.deletion class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0017_processor.py b/src/ralph/assets/migrations/0017_processor.py index f58fd517a6..bbc73da9b1 100644 --- a/src/ralph/assets/migrations/0017_processor.py +++ b/src/ralph/assets/migrations/0017_processor.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0018_disk.py b/src/ralph/assets/migrations/0018_disk.py index 37a0470307..c6f726ff5e 100644 --- a/src/ralph/assets/migrations/0018_disk.py +++ b/src/ralph/assets/migrations/0018_disk.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0019_auto_20160719_1443.py b/src/ralph/assets/migrations/0019_auto_20160719_1443.py index d51ba0bd13..6800106eed 100644 --- a/src/ralph/assets/migrations/0019_auto_20160719_1443.py +++ b/src/ralph/assets/migrations/0019_auto_20160719_1443.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations import re -import ralph.lib.mixins.fields + import django.core.validators +from django.db import migrations + +import ralph.lib.mixins.fields class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0022_auto_20160823_0921.py b/src/ralph/assets/migrations/0022_auto_20160823_0921.py index 185c049d96..a20fba9d36 100644 --- a/src/ralph/assets/migrations/0022_auto_20160823_0921.py +++ b/src/ralph/assets/migrations/0022_auto_20160823_0921.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/assets/migrations/0024_auto_20170322_1148.py b/src/ralph/assets/migrations/0024_auto_20170322_1148.py index b3b9313192..2c7fdea1e5 100644 --- a/src/ralph/assets/migrations/0024_auto_20170322_1148.py +++ b/src/ralph/assets/migrations/0024_auto_20170322_1148.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0025_auto_20170331_1341.py b/src/ralph/assets/migrations/0025_auto_20170331_1341.py index a964be2987..bbbff479cf 100644 --- a/src/ralph/assets/migrations/0025_auto_20170331_1341.py +++ b/src/ralph/assets/migrations/0025_auto_20170331_1341.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0026_auto_20170510_0840.py b/src/ralph/assets/migrations/0026_auto_20170510_0840.py index 291907b034..edcfc43a59 100644 --- a/src/ralph/assets/migrations/0026_auto_20170510_0840.py +++ b/src/ralph/assets/migrations/0026_auto_20170510_0840.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/assets/migrations/0031_auto_20200728_1326.py b/src/ralph/assets/migrations/0031_auto_20200728_1326.py index 94146e525d..8d175d4616 100644 --- a/src/ralph/assets/migrations/0031_auto_20200728_1326.py +++ b/src/ralph/assets/migrations/0031_auto_20200728_1326.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0032_auto_20200909_1012.py b/src/ralph/assets/migrations/0032_auto_20200909_1012.py index 9242c63f2d..18e9e20def 100644 --- a/src/ralph/assets/migrations/0032_auto_20200909_1012.py +++ b/src/ralph/assets/migrations/0032_auto_20200909_1012.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import djmoney.models.fields from decimal import Decimal +import djmoney.models.fields +from django.db import migrations + class Migration(migrations.Migration): dependencies = [ diff --git a/src/ralph/assets/migrations/0033_auto_20211115_1125.py b/src/ralph/assets/migrations/0033_auto_20211115_1125.py index 7ca949a780..2a2dec8f29 100644 --- a/src/ralph/assets/migrations/0033_auto_20211115_1125.py +++ b/src/ralph/assets/migrations/0033_auto_20211115_1125.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/assets/migrations/0035_auto_20240506_1633.py b/src/ralph/assets/migrations/0035_auto_20240506_1633.py index 29a5f885ab..993470dba2 100644 --- a/src/ralph/assets/migrations/0035_auto_20240506_1633.py +++ b/src/ralph/assets/migrations/0035_auto_20240506_1633.py @@ -2,8 +2,8 @@ # Generated by Django 1.9.13 on 2024-05-06 16:33 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/assets/migrations/0036_auto_20240904_1126.py b/src/ralph/assets/migrations/0036_auto_20240904_1126.py index 49631a301e..b68b53cf31 100644 --- a/src/ralph/assets/migrations/0036_auto_20240904_1126.py +++ b/src/ralph/assets/migrations/0036_auto_20240904_1126.py @@ -4,6 +4,7 @@ import django.core.validators from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/assets/migrations/0037_auto_20240621_1217.py b/src/ralph/assets/migrations/0037_auto_20240621_1217.py index e2343b55c5..0e85291d83 100644 --- a/src/ralph/assets/migrations/0037_auto_20240621_1217.py +++ b/src/ralph/assets/migrations/0037_auto_20240621_1217.py @@ -1,7 +1,7 @@ # Generated by Django 2.0.13 on 2024-06-21 12:17 -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/assets/models/__init__.py b/src/ralph/assets/models/__init__.py index a030a2f448..23870cb468 100644 --- a/src/ralph/assets/models/__init__.py +++ b/src/ralph/assets/models/__init__.py @@ -1,8 +1,8 @@ from ralph.assets.models.assets import ( Asset, + AssetHolder, AssetLastHostname, AssetModel, - AssetHolder, BudgetInfo, BusinessSegment, Category, @@ -22,13 +22,13 @@ ObjectModelType, ) from ralph.assets.models.components import ( - ComponentModel, Component, + ComponentModel, Disk, - GenericComponent, Ethernet, - Memory, FibreChannelCard, + GenericComponent, + Memory, Processor, ) from ralph.assets.models.configuration import ConfigurationClass, ConfigurationModule diff --git a/src/ralph/assets/subscribers.py b/src/ralph/assets/subscribers.py index ea49e62ba8..c175a79f35 100644 --- a/src/ralph/assets/subscribers.py +++ b/src/ralph/assets/subscribers.py @@ -2,7 +2,6 @@ import logging import pyhermes - from django.conf import settings from django.contrib.auth import get_user_model diff --git a/src/ralph/assets/tests/test_api.py b/src/ralph/assets/tests/test_api.py index b8a2bef720..60bb50bfd7 100644 --- a/src/ralph/assets/tests/test_api.py +++ b/src/ralph/assets/tests/test_api.py @@ -36,7 +36,7 @@ from ralph.back_office.tests.factories import BackOfficeAssetFactory from ralph.configuration_management.models import SCMCheckResult from ralph.configuration_management.tests.factories import SCMStatusCheckFactory -from ralph.data_center.models import Cluster, Database, DataCenterAsset, VIP +from ralph.data_center.models import VIP, Cluster, Database, DataCenterAsset from ralph.data_center.tests.factories import ( ClusterFactory, DatabaseFactory, diff --git a/src/ralph/attachments/migrations/0001_initial.py b/src/ralph/attachments/migrations/0001_initial.py index 29c04ce282..9e34e3c7ea 100644 --- a/src/ralph/attachments/migrations/0001_initial.py +++ b/src/ralph/attachments/migrations/0001_initial.py @@ -2,8 +2,9 @@ from __future__ import unicode_literals import django -from django.db import migrations, models from django.conf import settings +from django.db import migrations, models + import ralph.attachments.helpers diff --git a/src/ralph/attachments/migrations/0003_auto_20160121_1346.py b/src/ralph/attachments/migrations/0003_auto_20160121_1346.py index feceb1684a..dcf6dc295a 100644 --- a/src/ralph/attachments/migrations/0003_auto_20160121_1346.py +++ b/src/ralph/attachments/migrations/0003_auto_20160121_1346.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + from ralph.admin.helpers import get_content_type_for_model diff --git a/src/ralph/attachments/tests/__init__.py b/src/ralph/attachments/tests/__init__.py index ee00ea4ca2..b6f59cbf3d 100644 --- a/src/ralph/attachments/tests/__init__.py +++ b/src/ralph/attachments/tests/__init__.py @@ -2,14 +2,13 @@ import random from django.apps import apps -from django.test import TestCase from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile +from django.test import TestCase from ralph.attachments.models import Attachment, AttachmentItem - User = apps.get_model(*settings.AUTH_USER_MODEL.split(".")) diff --git a/src/ralph/back_office/migrations/0001_initial.py b/src/ralph/back_office/migrations/0001_initial.py index ce81bf0062..2e890abd6f 100644 --- a/src/ralph/back_office/migrations/0001_initial.py +++ b/src/ralph/back_office/migrations/0001_initial.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -from django.conf import settings import django.db.models.deletion -import ralph.lib.transitions.fields +from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.fields +import ralph.lib.transitions.fields class Migration(migrations.Migration): diff --git a/src/ralph/back_office/migrations/0007_auto_20180105_0910.py b/src/ralph/back_office/migrations/0007_auto_20180105_0910.py index 28c7053084..efa85e3eee 100644 --- a/src/ralph/back_office/migrations/0007_auto_20180105_0910.py +++ b/src/ralph/back_office/migrations/0007_auto_20180105_0910.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0008_auto_20180801_1157.py b/src/ralph/back_office/migrations/0008_auto_20180801_1157.py index 354156703b..a26a42be04 100644 --- a/src/ralph/back_office/migrations/0008_auto_20180801_1157.py +++ b/src/ralph/back_office/migrations/0008_auto_20180801_1157.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0009_auto_20181016_1252.py b/src/ralph/back_office/migrations/0009_auto_20181016_1252.py index dc2f4adc9e..191e7b3391 100644 --- a/src/ralph/back_office/migrations/0009_auto_20181016_1252.py +++ b/src/ralph/back_office/migrations/0009_auto_20181016_1252.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py b/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py index ca7bb23ab6..bfb7c9146a 100644 --- a/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py +++ b/src/ralph/back_office/migrations/0010_backofficeasset_imei2.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/back_office/migrations/0011_auto_20190517_1115.py b/src/ralph/back_office/migrations/0011_auto_20190517_1115.py index a18bbc45cd..0e264a0062 100644 --- a/src/ralph/back_office/migrations/0011_auto_20190517_1115.py +++ b/src/ralph/back_office/migrations/0011_auto_20190517_1115.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/back_office/migrations/0012_auto_20210318_1230.py b/src/ralph/back_office/migrations/0012_auto_20210318_1230.py index 726fbce358..76c86d3467 100644 --- a/src/ralph/back_office/migrations/0012_auto_20210318_1230.py +++ b/src/ralph/back_office/migrations/0012_auto_20210318_1230.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0013_auto_20220421_1202.py b/src/ralph/back_office/migrations/0013_auto_20220421_1202.py index 01ee05927d..8f899c083a 100644 --- a/src/ralph/back_office/migrations/0013_auto_20220421_1202.py +++ b/src/ralph/back_office/migrations/0013_auto_20220421_1202.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0014_auto_20221108_1007.py b/src/ralph/back_office/migrations/0014_auto_20221108_1007.py index 98b027eab8..b7a0658a9c 100644 --- a/src/ralph/back_office/migrations/0014_auto_20221108_1007.py +++ b/src/ralph/back_office/migrations/0014_auto_20221108_1007.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0015_auto_20221207_1445.py b/src/ralph/back_office/migrations/0015_auto_20221207_1445.py index c823f0feea..1f255d0616 100644 --- a/src/ralph/back_office/migrations/0015_auto_20221207_1445.py +++ b/src/ralph/back_office/migrations/0015_auto_20221207_1445.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0016_auto_20221220_1210.py b/src/ralph/back_office/migrations/0016_auto_20221220_1210.py index a9e1be6a4f..7c2107056d 100644 --- a/src/ralph/back_office/migrations/0016_auto_20221220_1210.py +++ b/src/ralph/back_office/migrations/0016_auto_20221220_1210.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0017_auto_20230112_0949.py b/src/ralph/back_office/migrations/0017_auto_20230112_0949.py index fd874877d2..b0b1507173 100644 --- a/src/ralph/back_office/migrations/0017_auto_20230112_0949.py +++ b/src/ralph/back_office/migrations/0017_auto_20230112_0949.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0018_auto_20230206_1020.py b/src/ralph/back_office/migrations/0018_auto_20230206_1020.py index 577dc3d571..83212e6743 100644 --- a/src/ralph/back_office/migrations/0018_auto_20230206_1020.py +++ b/src/ralph/back_office/migrations/0018_auto_20230206_1020.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0020_auto_20230419_1223.py b/src/ralph/back_office/migrations/0020_auto_20230419_1223.py index 3a1e2fa629..2b6b6d781d 100644 --- a/src/ralph/back_office/migrations/0020_auto_20230419_1223.py +++ b/src/ralph/back_office/migrations/0020_auto_20230419_1223.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import datetime + import django from django.db import migrations -import datetime def forwards_func(apps, schema_editor): diff --git a/src/ralph/back_office/migrations/0021_auto_20230511_1202.py b/src/ralph/back_office/migrations/0021_auto_20230511_1202.py index d1642afdee..539cc231e0 100644 --- a/src/ralph/back_office/migrations/0021_auto_20230511_1202.py +++ b/src/ralph/back_office/migrations/0021_auto_20230511_1202.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0022_auto_20230616_1235.py b/src/ralph/back_office/migrations/0022_auto_20230616_1235.py index de2ae05960..9ff2d7bdcd 100644 --- a/src/ralph/back_office/migrations/0022_auto_20230616_1235.py +++ b/src/ralph/back_office/migrations/0022_auto_20230616_1235.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0023_auto_20240223_1018.py b/src/ralph/back_office/migrations/0023_auto_20240223_1018.py index a10359a959..ed5be234fc 100644 --- a/src/ralph/back_office/migrations/0023_auto_20240223_1018.py +++ b/src/ralph/back_office/migrations/0023_auto_20240223_1018.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/back_office/migrations/0024_auto_20240621_1217.py b/src/ralph/back_office/migrations/0024_auto_20240621_1217.py index 599a167e52..e4d4a6da41 100644 --- a/src/ralph/back_office/migrations/0024_auto_20240621_1217.py +++ b/src/ralph/back_office/migrations/0024_auto_20240621_1217.py @@ -1,7 +1,7 @@ # Generated by Django 2.0.13 on 2024-06-21 12:17 -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/back_office/tests/test_models.py b/src/ralph/back_office/tests/test_models.py index 067158e52a..c8e67b0aa6 100644 --- a/src/ralph/back_office/tests/test_models.py +++ b/src/ralph/back_office/tests/test_models.py @@ -8,7 +8,7 @@ from django.contrib.messages.storage.fallback import FallbackStorage from django.core import mail from django.core.files.uploadedfile import SimpleUploadedFile -from django.test import override_settings, RequestFactory, SimpleTestCase +from django.test import RequestFactory, SimpleTestCase, override_settings from django.urls import reverse from django.utils import timezone @@ -25,20 +25,20 @@ from ralph.attachments.models import Attachment from ralph.back_office.helpers import EmailContext from ralph.back_office.models import ( - _check_assets_owner, BackOfficeAsset, BackOfficeAssetStatus, + _check_assets_owner, ) from ralph.back_office.tests.factories import BackOfficeAssetFactory from ralph.data_center.models import DataCenterAsset, DataCenterAssetStatus from ralph.data_center.tests.factories import RackFactory from ralph.lib.external_services import ExternalService from ralph.lib.transitions.models import ( - _check_instances_for_transition, - run_field_transition, Transition, TransitionModel, TransitionNotAllowedError, + _check_instances_for_transition, + run_field_transition, ) from ralph.lib.transitions.tests import TransitionTestCase from ralph.licences.tests.factories import LicenceFactory diff --git a/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py b/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py index 5ab3e7f586..a6c052ab3b 100644 --- a/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py +++ b/src/ralph/configuration_management/migrations/0002_auto_20170622_1254.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import dj.choices.fields from django.db import migrations + import ralph.configuration_management.models -import dj.choices.fields class Migration(migrations.Migration): diff --git a/src/ralph/configuration_management/views.py b/src/ralph/configuration_management/views.py index 735ed41488..9b76353b9f 100644 --- a/src/ralph/configuration_management/views.py +++ b/src/ralph/configuration_management/views.py @@ -14,7 +14,6 @@ # NOTE(romcheg): These functions could be moved to a common place from ralph.security.views import _linkify, _url_name_for_change_view - logger = logging.getLogger(__name__) diff --git a/src/ralph/dashboards/api/views.py b/src/ralph/dashboards/api/views.py index 13de85e9c3..8366026377 100644 --- a/src/ralph/dashboards/api/views.py +++ b/src/ralph/dashboards/api/views.py @@ -1,4 +1,5 @@ from rest_framework.viewsets import ReadOnlyModelViewSet + from ralph.dashboards.api.serializers import GraphSerializer, GraphSerializerDetail from ralph.dashboards.models import Graph diff --git a/src/ralph/dashboards/migrations/0001_initial.py b/src/ralph/dashboards/migrations/0001_initial.py index 91cb042459..002c629f07 100644 --- a/src/ralph/dashboards/migrations/0001_initial.py +++ b/src/ralph/dashboards/migrations/0001_initial.py @@ -2,8 +2,8 @@ from __future__ import unicode_literals import django -from django.db import migrations, models import django_extensions.db.fields.json +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py b/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py index 5f0dcc293a..d4852c2548 100644 --- a/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py +++ b/src/ralph/dashboards/migrations/0007_auto_20240723_1148.py @@ -2,8 +2,8 @@ # Generated by Django 1.10.8 on 2024-07-23 11:48 from __future__ import unicode_literals -from django.db import migrations from django.core.cache import caches +from django.db import migrations def clear_sitetree_cache(apps, schema_editor): diff --git a/src/ralph/data_center/admin.py b/src/ralph/data_center/admin.py index 925e477cbf..3090df6b14 100644 --- a/src/ralph/data_center/admin.py +++ b/src/ralph/data_center/admin.py @@ -4,7 +4,7 @@ from django.conf import settings from django.contrib.admin import SimpleListFilter -from django.contrib.admin.views.main import ChangeList, ORDER_VAR +from django.contrib.admin.views.main import ORDER_VAR, ChangeList from django.contrib.contenttypes.models import ContentType from django.db.models import Prefetch, Q from django.urls import reverse @@ -56,11 +56,11 @@ ServerRoom, ) from ralph.data_center.models.virtual import ( + VIP, BaseObjectCluster, Cluster, ClusterType, Database, - VIP, ) from ralph.data_center.views import RelationsView from ralph.data_importer import resources diff --git a/src/ralph/data_center/api/serializers.py b/src/ralph/data_center/api/serializers.py index efcf2fdd5a..55335f4bea 100644 --- a/src/ralph/data_center/api/serializers.py +++ b/src/ralph/data_center/api/serializers.py @@ -13,6 +13,7 @@ ) from ralph.configuration_management.api import SCMInfoSerializer from ralph.data_center.models import ( + VIP, Accessory, BaseObjectCluster, Cluster, @@ -23,7 +24,6 @@ Rack, RackAccessory, ServerRoom, - VIP, ) from ralph.security.api import SecurityScanSerializer @@ -133,8 +133,10 @@ class DataCenterAssetSerializer(ComponentSerializerMixin, AssetSerializer): related_hosts = serializers.SerializerMethodField() def get_related_hosts(self, obj): - from ralph.virtual.api import CloudHostSimpleSerializer - from ralph.virtual.api import VirtualServerSimpleSerializer + from ralph.virtual.api import ( + CloudHostSimpleSerializer, + VirtualServerSimpleSerializer, + ) # attributes "virtual_servers", "physical_servers" and "cloud_hosts" # are custom prefetches, see DataCenterAssetViewSet diff --git a/src/ralph/data_center/api/views.py b/src/ralph/data_center/api/views.py index d0c9e276f5..c5c2af8057 100644 --- a/src/ralph/data_center/api/views.py +++ b/src/ralph/data_center/api/views.py @@ -5,8 +5,8 @@ from ralph.api import RalphAPIViewSet from ralph.assets.api.filters import NetworkableObjectFilters from ralph.assets.api.views import ( - base_object_descendant_prefetch_related, BaseObjectViewSetMixin, + base_object_descendant_prefetch_related, ) from ralph.assets.models import ( ConfigurationClass, @@ -30,6 +30,7 @@ VIPSerializer, ) from ralph.data_center.models import ( + VIP, Accessory, BaseObjectCluster, Cluster, @@ -40,7 +41,6 @@ Rack, RackAccessory, ServerRoom, - VIP, ) from ralph.virtual.models import CloudHost, VirtualServer diff --git a/src/ralph/data_center/apps.py b/src/ralph/data_center/apps.py index 7b8c65f7d1..e24a3c18bc 100644 --- a/src/ralph/data_center/apps.py +++ b/src/ralph/data_center/apps.py @@ -1,4 +1,5 @@ from django.conf import settings + from ralph.apps import RalphAppConfig diff --git a/src/ralph/data_center/migrations/0001_initial.py b/src/ralph/data_center/migrations/0001_initial.py index e58dee67b3..1d1e4a8556 100644 --- a/src/ralph/data_center/migrations/0001_initial.py +++ b/src/ralph/data_center/migrations/0001_initial.py @@ -1,14 +1,16 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -import django.db.models.deletion +import re + import django.core.validators +import django.db.models.deletion +from django.db import migrations, models + +import ralph.lib.mixins.fields import ralph.lib.mixins.models import ralph.lib.transitions.fields -import re import ralph.networks.models.networks -import ralph.lib.mixins.fields class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0003_auto_20151126_2222.py b/src/ralph/data_center/migrations/0003_auto_20151126_2222.py index 90856c5863..8ce14852fb 100644 --- a/src/ralph/data_center/migrations/0003_auto_20151126_2222.py +++ b/src/ralph/data_center/migrations/0003_auto_20151126_2222.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/data_center/migrations/0005_auto_20160121_1133.py b/src/ralph/data_center/migrations/0005_auto_20160121_1133.py index 5ad5082425..9d8535acec 100644 --- a/src/ralph/data_center/migrations/0005_auto_20160121_1133.py +++ b/src/ralph/data_center/migrations/0005_auto_20160121_1133.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + from ralph.data_center.models.physical import ACCESSORY_DATA diff --git a/src/ralph/data_center/migrations/0009_auto_20160419_1003.py b/src/ralph/data_center/migrations/0009_auto_20160419_1003.py index bfcb28cecd..f8f8f096bb 100644 --- a/src/ralph/data_center/migrations/0009_auto_20160419_1003.py +++ b/src/ralph/data_center/migrations/0009_auto_20160419_1003.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/data_center/migrations/0011_change_networks_models.py b/src/ralph/data_center/migrations/0011_change_networks_models.py index 5682512916..ffc4b75340 100644 --- a/src/ralph/data_center/migrations/0011_change_networks_models.py +++ b/src/ralph/data_center/migrations/0011_change_networks_models.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +import django.db.models.deletion import mptt.fields +from django.db import migrations, models + import ralph.networks.fields -import django.db.models.deletion class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0013_auto_20160606_1438.py b/src/ralph/data_center/migrations/0013_auto_20160606_1438.py index 2a0da28133..6bfe23c818 100644 --- a/src/ralph/data_center/migrations/0013_auto_20160606_1438.py +++ b/src/ralph/data_center/migrations/0013_auto_20160606_1438.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -import ralph.lib.transitions.fields import datetime + +from django.db import migrations, models + import ralph.lib.mixins.fields +import ralph.lib.transitions.fields class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0021_auto_20161003_0751.py b/src/ralph/data_center/migrations/0021_auto_20161003_0751.py index c00c669a0d..65524d3651 100644 --- a/src/ralph/data_center/migrations/0021_auto_20161003_0751.py +++ b/src/ralph/data_center/migrations/0021_auto_20161003_0751.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.core.validators +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0022_auto_20161206_1521.py b/src/ralph/data_center/migrations/0022_auto_20161206_1521.py index 5f33f8471d..78e7690f05 100644 --- a/src/ralph/data_center/migrations/0022_auto_20161206_1521.py +++ b/src/ralph/data_center/migrations/0022_auto_20161206_1521.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py b/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py index a898a28f40..5411c795a4 100644 --- a/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py +++ b/src/ralph/data_center/migrations/0023_rack_reverse_ordering.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0024_auto_20170331_1341.py b/src/ralph/data_center/migrations/0024_auto_20170331_1341.py index 1d8358d753..3917c7c228 100644 --- a/src/ralph/data_center/migrations/0024_auto_20170331_1341.py +++ b/src/ralph/data_center/migrations/0024_auto_20170331_1341.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0025_auto_20170510_1122.py b/src/ralph/data_center/migrations/0025_auto_20170510_1122.py index 2b8fa24240..ddbd27a1d4 100644 --- a/src/ralph/data_center/migrations/0025_auto_20170510_1122.py +++ b/src/ralph/data_center/migrations/0025_auto_20170510_1122.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/data_center/migrations/0026_auto_20170614_1237.py b/src/ralph/data_center/migrations/0026_auto_20170614_1237.py index d024885361..3ba5ade8ec 100644 --- a/src/ralph/data_center/migrations/0026_auto_20170614_1237.py +++ b/src/ralph/data_center/migrations/0026_auto_20170614_1237.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0032_auto_20240521_1542.py b/src/ralph/data_center/migrations/0032_auto_20240521_1542.py index f7e1b406cf..d5628ff920 100644 --- a/src/ralph/data_center/migrations/0032_auto_20240521_1542.py +++ b/src/ralph/data_center/migrations/0032_auto_20240521_1542.py @@ -2,8 +2,8 @@ # Generated by Django 1.11.8 on 2024-05-21 15:42 from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/data_center/migrations/0033_auto_20240621_1217.py b/src/ralph/data_center/migrations/0033_auto_20240621_1217.py index b009a71ec9..c9a97741ff 100644 --- a/src/ralph/data_center/migrations/0033_auto_20240621_1217.py +++ b/src/ralph/data_center/migrations/0033_auto_20240621_1217.py @@ -1,8 +1,9 @@ # Generated by Django 2.0.13 on 2024-06-21 12:17 -from django.db import migrations import django.db.models.deletion import django.db.models.manager +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/data_center/migrations/0034_auto_20240628_1207.py b/src/ralph/data_center/migrations/0034_auto_20240628_1207.py index 6a2c9aa478..05033cae6c 100644 --- a/src/ralph/data_center/migrations/0034_auto_20240628_1207.py +++ b/src/ralph/data_center/migrations/0034_auto_20240628_1207.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-28 12:07 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/data_center/models/__init__.py b/src/ralph/data_center/models/__init__.py index a52f3e3a4f..136d3768cb 100644 --- a/src/ralph/data_center/models/__init__.py +++ b/src/ralph/data_center/models/__init__.py @@ -20,12 +20,12 @@ ServerRoom, ) from ralph.data_center.models.virtual import ( + VIP, BaseObjectCluster, Cluster, ClusterStatus, ClusterType, Database, - VIP, VIPProtocol, ) diff --git a/src/ralph/data_center/models/physical.py b/src/ralph/data_center/models/physical.py index dcbec967e6..f9d9a37a6e 100644 --- a/src/ralph/data_center/models/physical.py +++ b/src/ralph/data_center/models/physical.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import logging import re -from collections import namedtuple, OrderedDict +from collections import OrderedDict, namedtuple from itertools import chain from dj.choices import Choices, Country diff --git a/src/ralph/data_center/publishers.py b/src/ralph/data_center/publishers.py index 3ec758abc9..611421b352 100644 --- a/src/ralph/data_center/publishers.py +++ b/src/ralph/data_center/publishers.py @@ -10,8 +10,10 @@ def _get_host_data(instance): - from ralph.assets.api.serializers_dchosts import DCHostPhysicalSerializer - from ralph.assets.api.serializers_dchosts import DCHostSerializer + from ralph.assets.api.serializers_dchosts import ( + DCHostPhysicalSerializer, + DCHostSerializer, + ) from ralph.data_center.models import DataCenterAsset if isinstance(instance, DataCenterAsset): diff --git a/src/ralph/data_center/subscribers.py b/src/ralph/data_center/subscribers.py index 99bb760241..f2e4d82014 100644 --- a/src/ralph/data_center/subscribers.py +++ b/src/ralph/data_center/subscribers.py @@ -7,7 +7,7 @@ from django.db import transaction from ralph.assets.models.assets import ServiceEnvironment -from ralph.data_center.models import Cluster, ClusterType, VIP, VIPProtocol +from ralph.data_center.models import VIP, Cluster, ClusterType, VIPProtocol from ralph.networks.models.networks import Ethernet, IPAddress logger = logging.getLogger(__name__) diff --git a/src/ralph/data_center/tests/factories.py b/src/ralph/data_center/tests/factories.py index 5d4731290a..4229eef09e 100644 --- a/src/ralph/data_center/tests/factories.py +++ b/src/ralph/data_center/tests/factories.py @@ -23,8 +23,8 @@ from ralph.data_center.models.choices import ConnectionType from ralph.data_center.models.components import DiskShare, DiskShareMount from ralph.data_center.models.physical import ( - Accessory, ACCESSORY_DATA, + Accessory, Connection, DataCenter, DataCenterAsset, @@ -33,10 +33,10 @@ ServerRoom, ) from ralph.data_center.models.virtual import ( + VIP, Cluster, ClusterType, Database, - VIP, VIPProtocol, ) from ralph.security.tests.factories import SecurityScanFactory diff --git a/src/ralph/data_center/tests/test_admin.py b/src/ralph/data_center/tests/test_admin.py index 46b87bec4a..79127af3c0 100644 --- a/src/ralph/data_center/tests/test_admin.py +++ b/src/ralph/data_center/tests/test_admin.py @@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model from django.core import mail from django.db import connection, transaction -from django.test import override_settings, RequestFactory, TransactionTestCase +from django.test import RequestFactory, TransactionTestCase, override_settings from ralph.accounts.tests.factories import UserFactory from ralph.assets.tests.factories import ServiceEnvironmentFactory, ServiceFactory diff --git a/src/ralph/data_center/tests/test_api.py b/src/ralph/data_center/tests/test_api.py index c84a455fc8..569f7d706d 100644 --- a/src/ralph/data_center/tests/test_api.py +++ b/src/ralph/data_center/tests/test_api.py @@ -29,7 +29,6 @@ ServerRoomFactory, ) from ralph.networks.tests.factories import IPAddressFactory - from ralph.virtual.tests.factories import CloudHostFactory, VirtualServerFactory diff --git a/src/ralph/data_center/tests/test_models.py b/src/ralph/data_center/tests/test_models.py index 244c308ba2..4f1f9005f5 100644 --- a/src/ralph/data_center/tests/test_models.py +++ b/src/ralph/data_center/tests/test_models.py @@ -9,8 +9,8 @@ from ralph.back_office.tests.factories import WarehouseFactory from ralph.data_center.models.choices import DataCenterAssetStatus, Orientation from ralph.data_center.models.physical import ( - assign_additional_hostname_choices, DataCenterAsset, + assign_additional_hostname_choices, ) from ralph.data_center.models.virtual import BaseObjectCluster from ralph.data_center.tests.factories import ( diff --git a/src/ralph/data_center/tests/test_subscribers.py b/src/ralph/data_center/tests/test_subscribers.py index 58d7ecc558..6d62be1b07 100644 --- a/src/ralph/data_center/tests/test_subscribers.py +++ b/src/ralph/data_center/tests/test_subscribers.py @@ -5,7 +5,7 @@ from django.test import TestCase from ralph.assets.tests.factories import ServiceEnvironmentFactory -from ralph.data_center.models import Cluster, VIP, VIPProtocol +from ralph.data_center.models import VIP, Cluster, VIPProtocol from ralph.data_center.subscribers import ( handle_create_vip_event, handle_delete_vip_event, diff --git a/src/ralph/data_importer/management/commands/create_server_model.py b/src/ralph/data_importer/management/commands/create_server_model.py index f3431f441c..6d14020862 100644 --- a/src/ralph/data_importer/management/commands/create_server_model.py +++ b/src/ralph/data_importer/management/commands/create_server_model.py @@ -2,7 +2,6 @@ from ralph.assets.models import AssetModel, Category, Manufacturer, ObjectModelType - DEFAULT_MODEL_CATEGORY = "generic server category" DEFAULT_MODEL_NAME = "Model A" DEFAULT_MODEL_MANUFACTURER = "Generic manufacturer" diff --git a/src/ralph/data_importer/management/commands/initial_data.py b/src/ralph/data_importer/management/commands/initial_data.py index d5385d0287..3c8353d2b0 100644 --- a/src/ralph/data_importer/management/commands/initial_data.py +++ b/src/ralph/data_importer/management/commands/initial_data.py @@ -1,7 +1,7 @@ import ipaddress from django.contrib.auth import get_user_model -from django.core.management import BaseCommand, call_command, CommandError +from django.core.management import BaseCommand, CommandError, call_command from django.db import transaction from ralph.accounts.tests.factories import RegionFactory diff --git a/src/ralph/data_importer/resources.py b/src/ralph/data_importer/resources.py index 40408a4e23..c776ec2d3f 100644 --- a/src/ralph/data_importer/resources.py +++ b/src/ralph/data_importer/resources.py @@ -6,7 +6,7 @@ from import_export import fields, resources, widgets from ralph.accounts.models import Region -from ralph.assets.models import assets, base, BaseObject, configuration +from ralph.assets.models import BaseObject, assets, base, configuration from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse from ralph.data_center.models import hosts, physical from ralph.data_importer.fields import PriceField, ThroughField diff --git a/src/ralph/deployment/deployment.py b/src/ralph/deployment/deployment.py index f4c2435e6d..653b3f2cbc 100644 --- a/src/ralph/deployment/deployment.py +++ b/src/ralph/deployment/deployment.py @@ -39,7 +39,7 @@ from ralph.dns.dnsaas import DNSaaS from ralph.dns.forms import RecordType from ralph.dns.views import DNSaaSIntegrationNotEnabledError -from ralph.lib.mixins.forms import ChoiceFieldWithOtherOption, OTHER +from ralph.lib.mixins.forms import OTHER, ChoiceFieldWithOtherOption from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.exceptions import FreezeAsyncTransition from ralph.networks.models import IPAddress, Network, NetworkEnvironment diff --git a/src/ralph/deployment/migrations/0001_initial.py b/src/ralph/deployment/migrations/0001_initial.py index 2d96bbd91c..e6985e214d 100644 --- a/src/ralph/deployment/migrations/0001_initial.py +++ b/src/ralph/deployment/migrations/0001_initial.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.deployment.models diff --git a/src/ralph/deployment/migrations/0005_auto_20180625_1257.py b/src/ralph/deployment/migrations/0005_auto_20180625_1257.py index dc83076cbb..ae7fd19188 100644 --- a/src/ralph/deployment/migrations/0005_auto_20180625_1257.py +++ b/src/ralph/deployment/migrations/0005_auto_20180625_1257.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/deployment/migrations/0007_auto_20240506_1633.py b/src/ralph/deployment/migrations/0007_auto_20240506_1633.py index 0c17197fc1..ec7c8cb61f 100644 --- a/src/ralph/deployment/migrations/0007_auto_20240506_1633.py +++ b/src/ralph/deployment/migrations/0007_auto_20240506_1633.py @@ -2,8 +2,8 @@ # Generated by Django 1.9.13 on 2024-05-06 16:33 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/deployment/migrations/0009_auto_20240924_1133.py b/src/ralph/deployment/migrations/0009_auto_20240924_1133.py index 56bc7fdc3a..ebe6aca67d 100644 --- a/src/ralph/deployment/migrations/0009_auto_20240924_1133.py +++ b/src/ralph/deployment/migrations/0009_auto_20240924_1133.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.polymorphic.fields diff --git a/src/ralph/deployment/tests/test_deployment.py b/src/ralph/deployment/tests/test_deployment.py index 06398cee74..9de8ffa8e6 100644 --- a/src/ralph/deployment/tests/test_deployment.py +++ b/src/ralph/deployment/tests/test_deployment.py @@ -3,7 +3,7 @@ from ddt import data, ddt, unpack from django.core.exceptions import ValidationError -from django.test import override_settings, TestCase +from django.test import TestCase, override_settings from ralph.assets.models import Ethernet from ralph.assets.tests.factories import ServiceEnvironmentFactory diff --git a/src/ralph/deployment/views.py b/src/ralph/deployment/views.py index 54a3f96ea2..b42bba832f 100644 --- a/src/ralph/deployment/views.py +++ b/src/ralph/deployment/views.py @@ -1,4 +1,5 @@ import logging + from django.core.exceptions import SuspiciousOperation from django.http import Http404, HttpResponse, HttpResponseRedirect diff --git a/src/ralph/dhcp/migrations/0004_add_dns_server_group.py b/src/ralph/dhcp/migrations/0004_add_dns_server_group.py index 18c380f035..9966cde144 100644 --- a/src/ralph/dhcp/migrations/0004_add_dns_server_group.py +++ b/src/ralph/dhcp/migrations/0004_add_dns_server_group.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/dhcp/tests/test_agent.py b/src/ralph/dhcp/tests/test_agent.py index b0f03bdc41..3cecfe9e5e 100644 --- a/src/ralph/dhcp/tests/test_agent.py +++ b/src/ralph/dhcp/tests/test_agent.py @@ -1,14 +1,13 @@ import logging from ddt import data, ddt, unpack +from dhcp_agent import Cache, DHCPConfigManager from django.contrib.auth import get_user_model from django.test import LiveServerTestCase -from dhcp_agent import Cache, DHCPConfigManager from ralph.data_center.tests.factories import DataCenterFactory from ralph.dhcp.models import DHCPServer - logger = logging.getLogger(__file__) diff --git a/src/ralph/dns/apps.py b/src/ralph/dns/apps.py index 3b84e8a3b8..95ca12d05e 100644 --- a/src/ralph/dns/apps.py +++ b/src/ralph/dns/apps.py @@ -1,4 +1,5 @@ from django.conf import settings + from ralph.apps import RalphAppConfig diff --git a/src/ralph/dns/dnsaas.py b/src/ralph/dns/dnsaas.py index ce5b3bff83..eca76d5997 100644 --- a/src/ralph/dns/dnsaas.py +++ b/src/ralph/dns/dnsaas.py @@ -5,6 +5,7 @@ from functools import wraps from typing import List, Optional, Tuple, Union from urllib.parse import parse_qs, urlencode, urljoin, urlsplit + import requests from dj.choices import Choices from django.conf import settings diff --git a/src/ralph/dns/tests.py b/src/ralph/dns/tests.py index 504e3cf7a3..69483c384a 100644 --- a/src/ralph/dns/tests.py +++ b/src/ralph/dns/tests.py @@ -2,14 +2,14 @@ from unittest.mock import patch from django.db import transaction -from django.test import override_settings, TestCase, TransactionTestCase +from django.test import TestCase, TransactionTestCase, override_settings from ralph.assets.tests.factories import ConfigurationClassFactory, EthernetFactory from ralph.data_center.models import BaseObjectCluster, DataCenterAsset from ralph.dns.dnsaas import DNSaaS from ralph.dns.forms import DNSRecordForm, RecordType from ralph.dns.publishers import _get_txt_data_to_publish_to_dnsaas -from ralph.dns.views import add_errors, DNSaaSIntegrationNotEnabledError, DNSView +from ralph.dns.views import DNSaaSIntegrationNotEnabledError, DNSView, add_errors from ralph.networks.tests.factories import IPAddressFactory from ralph.virtual.models import VirtualServer from ralph.virtual.tests.factories import VirtualServerFactory diff --git a/src/ralph/domains/apps.py b/src/ralph/domains/apps.py index 8812c65c38..e130734758 100644 --- a/src/ralph/domains/apps.py +++ b/src/ralph/domains/apps.py @@ -1,4 +1,5 @@ from django.conf import settings + from ralph.apps import RalphAppConfig diff --git a/src/ralph/domains/migrations/0001_initial.py b/src/ralph/domains/migrations/0001_initial.py index cafc61505a..08c2ba9c8a 100644 --- a/src/ralph/domains/migrations/0001_initial.py +++ b/src/ralph/domains/migrations/0001_initial.py @@ -2,8 +2,9 @@ from __future__ import unicode_literals import django -from django.db import migrations, models from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/domains/migrations/0005_auto_20170523_1214.py b/src/ralph/domains/migrations/0005_auto_20170523_1214.py index 4512c2226e..575bc1f07e 100644 --- a/src/ralph/domains/migrations/0005_auto_20170523_1214.py +++ b/src/ralph/domains/migrations/0005_auto_20170523_1214.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/domains/migrations/0006_auto_20180725_1216.py b/src/ralph/domains/migrations/0006_auto_20180725_1216.py index 9a61bd8bc4..f7891cf468 100644 --- a/src/ralph/domains/migrations/0006_auto_20180725_1216.py +++ b/src/ralph/domains/migrations/0006_auto_20180725_1216.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/domains/migrations/0007_auto_20200909_1012.py b/src/ralph/domains/migrations/0007_auto_20200909_1012.py index 53ad4ac141..2abafc6c84 100644 --- a/src/ralph/domains/migrations/0007_auto_20200909_1012.py +++ b/src/ralph/domains/migrations/0007_auto_20200909_1012.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import djmoney.models.fields from decimal import Decimal +import djmoney.models.fields +from django.db import migrations + class Migration(migrations.Migration): dependencies = [ diff --git a/src/ralph/domains/migrations/0008_auto_20240621_1011.py b/src/ralph/domains/migrations/0008_auto_20240621_1011.py index e5b85ef7ac..25a8bedd08 100644 --- a/src/ralph/domains/migrations/0008_auto_20240621_1011.py +++ b/src/ralph/domains/migrations/0008_auto_20240621_1011.py @@ -2,8 +2,8 @@ # Generated by Django 1.11.8 on 2024-06-21 10:11 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/domains/publishers.py b/src/ralph/domains/publishers.py index f3ff5e65e6..e72c90365e 100644 --- a/src/ralph/domains/publishers.py +++ b/src/ralph/domains/publishers.py @@ -8,7 +8,6 @@ from ralph.domains.models import Domain - logger = logging.getLogger(__name__) diff --git a/src/ralph/helpers.py b/src/ralph/helpers.py index a26ec0a719..2dd2673ff0 100644 --- a/src/ralph/helpers.py +++ b/src/ralph/helpers.py @@ -3,7 +3,7 @@ from functools import wraps from django.conf import settings -from django.core.cache import caches, DEFAULT_CACHE_ALIAS +from django.core.cache import DEFAULT_CACHE_ALIAS, caches from django.http import HttpResponse logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/api/exception_handler.py b/src/ralph/lib/api/exception_handler.py index ee0e9eac38..19c2c77394 100644 --- a/src/ralph/lib/api/exception_handler.py +++ b/src/ralph/lib/api/exception_handler.py @@ -1,5 +1,4 @@ from django.core.exceptions import ValidationError - from rest_framework.exceptions import ValidationError as DRFValidationError from rest_framework.views import exception_handler as drf_exception_handler diff --git a/src/ralph/lib/cache/__init__.py b/src/ralph/lib/cache/__init__.py index 342d2aa1f1..150428e5d7 100644 --- a/src/ralph/lib/cache/__init__.py +++ b/src/ralph/lib/cache/__init__.py @@ -2,7 +2,6 @@ DjangoConnectionPoolCache, ) - __all__ = [ 'DjangoConnectionPoolCache' ] diff --git a/src/ralph/lib/custom_fields/admin.py b/src/ralph/lib/custom_fields/admin.py index e5ea708cca..74f7a3cf49 100644 --- a/src/ralph/lib/custom_fields/admin.py +++ b/src/ralph/lib/custom_fields/admin.py @@ -8,7 +8,7 @@ from ralph.lib.custom_fields.forms import ( CustomFieldValueForm, CustomFieldValueFormSet, - CustomFieldValueWithClearChildrenForm + CustomFieldValueWithClearChildrenForm, ) from ralph.lib.custom_fields.models import CustomField, CustomFieldValue from ralph.lib.custom_fields.views import CustomFieldFormfieldView diff --git a/src/ralph/lib/custom_fields/api/routers.py b/src/ralph/lib/custom_fields/api/routers.py index 37e680373c..ad1f2f50b3 100644 --- a/src/ralph/lib/custom_fields/api/routers.py +++ b/src/ralph/lib/custom_fields/api/routers.py @@ -40,8 +40,9 @@ def _attach_nested_custom_fields(self, prefix, viewset, basename): particular model. """ # cyclic imports, meh - from .viewsets import ObjectCustomFieldsViewSet from ralph.api.viewsets import RalphAPIViewSet + + from .viewsets import ObjectCustomFieldsViewSet model = viewset.queryset.model custom_fields_related_viewset = type( '{}CustomFieldsViewSet'.format(model._meta.object_name), diff --git a/src/ralph/lib/custom_fields/api/serializers.py b/src/ralph/lib/custom_fields/api/serializers.py index bb24f3f95f..c2eeb67b97 100644 --- a/src/ralph/lib/custom_fields/api/serializers.py +++ b/src/ralph/lib/custom_fields/api/serializers.py @@ -4,7 +4,7 @@ from ralph.api.serializers import ( AdditionalLookupRelatedField, RalphAPISaveSerializer, - RalphAPISerializer + RalphAPISerializer, ) from ..models import CustomField, CustomFieldValue diff --git a/src/ralph/lib/custom_fields/api/viewsets.py b/src/ralph/lib/custom_fields/api/viewsets.py index d22e4dea22..7601b17b1d 100644 --- a/src/ralph/lib/custom_fields/api/viewsets.py +++ b/src/ralph/lib/custom_fields/api/viewsets.py @@ -4,10 +4,7 @@ from rest_framework.status import HTTP_403_FORBIDDEN from ..models import CustomFieldValue -from .serializers import ( - CustomFieldValueSaveSerializer, - CustomFieldValueSerializer -) +from .serializers import CustomFieldValueSaveSerializer, CustomFieldValueSerializer class ObjectCustomFieldsViewSet(viewsets.ModelViewSet): diff --git a/src/ralph/lib/custom_fields/fields.py b/src/ralph/lib/custom_fields/fields.py index 8617569d91..4aae85417b 100644 --- a/src/ralph/lib/custom_fields/fields.py +++ b/src/ralph/lib/custom_fields/fields.py @@ -4,8 +4,8 @@ from typing import Any from django.contrib.contenttypes.fields import ( + GenericRelation, create_generic_related_manager, - GenericRelation ) from django.contrib.contenttypes.models import ContentType from django.db import models diff --git a/src/ralph/lib/custom_fields/forms.py b/src/ralph/lib/custom_fields/forms.py index ea97ca5034..51e6319827 100644 --- a/src/ralph/lib/custom_fields/forms.py +++ b/src/ralph/lib/custom_fields/forms.py @@ -3,8 +3,8 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db.models import Q -from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext +from django.utils.translation import ugettext_lazy as _ class CustomFieldValueForm(forms.ModelForm): diff --git a/src/ralph/lib/custom_fields/migrations/0001_initial.py b/src/ralph/lib/custom_fields/migrations/0001_initial.py index 3097a5b48a..9e8ac6fcfc 100644 --- a/src/ralph/lib/custom_fields/migrations/0001_initial.py +++ b/src/ralph/lib/custom_fields/migrations/0001_initial.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/lib/custom_fields/models.py b/src/ralph/lib/custom_fields/models.py index 5cef68c91b..ea6bbd7946 100644 --- a/src/ralph/lib/custom_fields/models.py +++ b/src/ralph/lib/custom_fields/models.py @@ -1,11 +1,10 @@ import logging -import six +import six from dj.choices import Choices from django import forms from django.contrib.auth.models import Group from django.contrib.contenttypes import fields - from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db import models @@ -14,10 +13,8 @@ from django.utils.translation import ugettext_lazy as _ from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin -from .fields import ( - CustomFieldsWithInheritanceRelation, - CustomFieldValueQuerySet -) + +from .fields import CustomFieldsWithInheritanceRelation, CustomFieldValueQuerySet logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/custom_fields/signals.py b/src/ralph/lib/custom_fields/signals.py index 950890d92a..f7e9437c9d 100644 --- a/src/ralph/lib/custom_fields/signals.py +++ b/src/ralph/lib/custom_fields/signals.py @@ -1,6 +1,5 @@ from django.dispatch import Signal - # This signal is sent at the end of CustomFieldValueSaveSerializer's `create()` # method. api_post_create = Signal(providing_args=['instance']) diff --git a/src/ralph/lib/custom_fields/tests/api.py b/src/ralph/lib/custom_fields/tests/api.py index cf361d9ecf..202228d73d 100644 --- a/src/ralph/lib/custom_fields/tests/api.py +++ b/src/ralph/lib/custom_fields/tests/api.py @@ -4,7 +4,7 @@ from ..api import ( CustomFieldsFilterBackend, NestedCustomFieldsRouterMixin, - WithCustomFieldsSerializerMixin + WithCustomFieldsSerializerMixin, ) from .models import SomeModel diff --git a/src/ralph/lib/custom_fields/tests/factories.py b/src/ralph/lib/custom_fields/tests/factories.py index d584832382..68295f4e07 100644 --- a/src/ralph/lib/custom_fields/tests/factories.py +++ b/src/ralph/lib/custom_fields/tests/factories.py @@ -4,7 +4,7 @@ from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue + CustomFieldValue, ) diff --git a/src/ralph/lib/custom_fields/tests/test_api.py b/src/ralph/lib/custom_fields/tests/test_api.py index f0dfd56838..0eaff03d1a 100644 --- a/src/ralph/lib/custom_fields/tests/test_api.py +++ b/src/ralph/lib/custom_fields/tests/test_api.py @@ -8,6 +8,7 @@ from ralph.accounts.models import RalphUser from ralph.accounts.tests.factories import GroupFactory from ralph.tests.factories import UserFactory + from ..models import CustomField, CustomFieldTypes, CustomFieldValue from ..signals import api_post_create, api_post_update from .models import ModelA, ModelB, SomeModel diff --git a/src/ralph/lib/external_services/__init__.py b/src/ralph/lib/external_services/__init__.py index fe8f70adbe..cb551ef1d0 100644 --- a/src/ralph/lib/external_services/__init__.py +++ b/src/ralph/lib/external_services/__init__.py @@ -1,5 +1,4 @@ from .base import ExternalService, InternalService from .helpers import obj_to_dict - __all__ = ['ExternalService', 'InternalService', 'obj_to_dict'] diff --git a/src/ralph/lib/external_services/migrations/0001_initial.py b/src/ralph/lib/external_services/migrations/0001_initial.py index bba0e4b356..64090cee0b 100644 --- a/src/ralph/lib/external_services/migrations/0001_initial.py +++ b/src/ralph/lib/external_services/migrations/0001_initial.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import uuid + +import django_extensions.db.fields.json from django.db import migrations, models + import ralph.lib.mixins.fields -import django_extensions.db.fields.json -import uuid class Migration(migrations.Migration): diff --git a/src/ralph/lib/hooks/__init__.py b/src/ralph/lib/hooks/__init__.py index 046963cb51..ca30eaebfd 100644 --- a/src/ralph/lib/hooks/__init__.py +++ b/src/ralph/lib/hooks/__init__.py @@ -1,6 +1,5 @@ from ralph.lib.hooks.main import get_hook, hook_name_to_env_name - default_app_config = 'ralph.lib.hooks.apps.HooksAppConfig' __all__ = [ diff --git a/src/ralph/lib/metrics/__init__.py b/src/ralph/lib/metrics/__init__.py index 197d3e89b5..c019566e82 100644 --- a/src/ralph/lib/metrics/__init__.py +++ b/src/ralph/lib/metrics/__init__.py @@ -1,6 +1,6 @@ from .collector import build_statsd_client, statsd -from .utils import mark from .middlewares import patch_cursor +from .utils import mark __all__ = [ 'build_statsd_client', diff --git a/src/ralph/lib/metrics/collector.py b/src/ralph/lib/metrics/collector.py index 366c2cb308..b60d7f6e81 100644 --- a/src/ralph/lib/metrics/collector.py +++ b/src/ralph/lib/metrics/collector.py @@ -2,7 +2,7 @@ from contextlib import ContextDecorator from django.conf import settings -from statsd import defaults, StatsClient +from statsd import StatsClient, defaults logger = logging.getLogger(__name__) statsd = None diff --git a/src/ralph/lib/metrics/middlewares.py b/src/ralph/lib/metrics/middlewares.py index 41c71a552c..0741ee84b5 100644 --- a/src/ralph/lib/metrics/middlewares.py +++ b/src/ralph/lib/metrics/middlewares.py @@ -3,11 +3,12 @@ import threading import time from collections import deque -from resource import getrusage, RUSAGE_SELF +from resource import RUSAGE_SELF, getrusage from django.conf import settings from django.db.backends.utils import CursorWrapper from django.utils.deprecation import MiddlewareMixin + from .collector import statsd PROCESSING_TIME_METRIC_PREFIX = getattr( diff --git a/src/ralph/lib/mixins/fields.py b/src/ralph/lib/mixins/fields.py index 642de66bda..64be8fa6df 100644 --- a/src/ralph/lib/mixins/fields.py +++ b/src/ralph/lib/mixins/fields.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- import netaddr - from django import forms from django.apps import apps from django.conf import settings diff --git a/src/ralph/lib/mixins/tests/migrations/0001_initial.py b/src/ralph/lib/mixins/tests/migrations/0001_initial.py index 0b4e020940..0896d7450c 100644 --- a/src/ralph/lib/mixins/tests/migrations/0001_initial.py +++ b/src/ralph/lib/mixins/tests/migrations/0001_initial.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/lib/mixins/tests/test_api.py b/src/ralph/lib/mixins/tests/test_api.py index 53b4e9f5c9..ff5f334ed6 100644 --- a/src/ralph/lib/mixins/tests/test_api.py +++ b/src/ralph/lib/mixins/tests/test_api.py @@ -1,7 +1,7 @@ from django.test import TestCase from rest_framework.exceptions import ValidationError -from ..api import ChoiceFieldWithOtherOptionField, OTHER +from ..api import OTHER, ChoiceFieldWithOtherOptionField class TestChoiceFieldWithOtherOptionSerializer(TestCase): diff --git a/src/ralph/lib/openstack/client.py b/src/ralph/lib/openstack/client.py index 3bd41f1b37..7e16a91956 100644 --- a/src/ralph/lib/openstack/client.py +++ b/src/ralph/lib/openstack/client.py @@ -8,10 +8,10 @@ from ralph.settings import DEFAULT_OPENSTACK_PROVIDER_NAME try: - from keystoneclient.v2_0 import client as ks_v2_client - from keystoneclient.v3 import client as ks_v3_client from keystoneauth1 import session as ks_session from keystoneauth1.identity import v3 as ks_v3_identity + from keystoneclient.v2_0 import client as ks_v2_client + from keystoneclient.v3 import client as ks_v3_client keystone_client_exists = True except ImportError: keystone_client_exists = False diff --git a/src/ralph/lib/permissions/admin.py b/src/ralph/lib/permissions/admin.py index db49348e0d..0ff3c2b39d 100644 --- a/src/ralph/lib/permissions/admin.py +++ b/src/ralph/lib/permissions/admin.py @@ -7,10 +7,7 @@ from django.db.models.query import QuerySet from ralph.lib.mixins.forms import RequestFormMixin -from ralph.lib.permissions.models import ( - PermByFieldMixin, - PermissionsForObjectMixin -) +from ralph.lib.permissions.models import PermByFieldMixin, PermissionsForObjectMixin logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/permissions/api.py b/src/ralph/lib/permissions/api.py index 5aa40f14a7..c803fce4e5 100644 --- a/src/ralph/lib/permissions/api.py +++ b/src/ralph/lib/permissions/api.py @@ -10,10 +10,7 @@ from rest_framework.filters import BaseFilterBackend from rest_framework.permissions import IsAuthenticated as DRFIsAuthenticated -from ralph.lib.permissions.models import ( - PermByFieldMixin, - PermissionsForObjectMixin -) +from ralph.lib.permissions.models import PermByFieldMixin, PermissionsForObjectMixin ADD_PERM = ['%(app_label)s.add_%(model_name)s'] CHANGE_PERM = ['%(app_label)s.change_%(model_name)s'] diff --git a/src/ralph/lib/permissions/tests/api.py b/src/ralph/lib/permissions/tests/api.py index ed848461b2..f765d1928e 100644 --- a/src/ralph/lib/permissions/tests/api.py +++ b/src/ralph/lib/permissions/tests/api.py @@ -7,14 +7,9 @@ ObjectPermissionsMixin, PermissionsForObjectFilter, PermissionsPerFieldSerializerMixin, - RelatedObjectsPermissionsSerializerMixin -) -from ralph.lib.permissions.tests.models import ( - Article, - Foo, - Library, - LongArticle + RelatedObjectsPermissionsSerializerMixin, ) +from ralph.lib.permissions.tests.models import Article, Foo, Library, LongArticle class Permission(ObjectPermissionsMixin, permissions.IsAuthenticated): diff --git a/src/ralph/lib/permissions/tests/migrations/0001_initial.py b/src/ralph/lib/permissions/tests/migrations/0001_initial.py index 8ade138de5..045c1f284a 100644 --- a/src/ralph/lib/permissions/tests/migrations/0001_initial.py +++ b/src/ralph/lib/permissions/tests/migrations/0001_initial.py @@ -2,8 +2,8 @@ from __future__ import unicode_literals import django -from django.db import migrations, models from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/lib/permissions/tests/models.py b/src/ralph/lib/permissions/tests/models.py index 842e25dab9..32084dbe33 100644 --- a/src/ralph/lib/permissions/tests/models.py +++ b/src/ralph/lib/permissions/tests/models.py @@ -5,7 +5,7 @@ from ralph.lib.permissions.models import ( PermByFieldMixin, PermissionsForObjectMixin, - user_permission + user_permission, ) diff --git a/src/ralph/lib/permissions/tests/test_permissions_per_object.py b/src/ralph/lib/permissions/tests/test_permissions_per_object.py index c020e14c03..5b6bb23346 100644 --- a/src/ralph/lib/permissions/tests/test_permissions_per_object.py +++ b/src/ralph/lib/permissions/tests/test_permissions_per_object.py @@ -8,11 +8,11 @@ from ralph.lib.permissions.tests._base import PermissionsTestMixin from ralph.lib.permissions.tests.models import ( Article, + Library, + LongArticle, has_long_title, is_author, is_collabolator, - Library, - LongArticle ) diff --git a/src/ralph/lib/polymorphic/tests/migrations/0003_auto_20240506_1133.py b/src/ralph/lib/polymorphic/tests/migrations/0003_auto_20240506_1133.py index dc2ce82887..61202b4c79 100644 --- a/src/ralph/lib/polymorphic/tests/migrations/0003_auto_20240506_1133.py +++ b/src/ralph/lib/polymorphic/tests/migrations/0003_auto_20240506_1133.py @@ -2,8 +2,8 @@ # Generated by Django 1.9.13 on 2024-05-06 11:33 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/lib/polymorphic/tests/migrations/0004_auto_20240924_1142.py b/src/ralph/lib/polymorphic/tests/migrations/0004_auto_20240924_1142.py index 14d3fc9955..44002b7663 100644 --- a/src/ralph/lib/polymorphic/tests/migrations/0004_auto_20240924_1142.py +++ b/src/ralph/lib/polymorphic/tests/migrations/0004_auto_20240924_1142.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.polymorphic.fields diff --git a/src/ralph/lib/polymorphic/tests/tests_models.py b/src/ralph/lib/polymorphic/tests/tests_models.py index 6f8532681d..db8b33913c 100644 --- a/src/ralph/lib/polymorphic/tests/tests_models.py +++ b/src/ralph/lib/polymorphic/tests/tests_models.py @@ -8,7 +8,7 @@ PolymorphicModelTest, PolymorphicModelTest2, SomeM2MModel, - SomethingRelated + SomethingRelated, ) diff --git a/src/ralph/lib/serializers/__init__.py b/src/ralph/lib/serializers/__init__.py index e6cb11b579..27a750adeb 100644 --- a/src/ralph/lib/serializers/__init__.py +++ b/src/ralph/lib/serializers/__init__.py @@ -6,7 +6,6 @@ from django.core.serializers.json import Serializer as JSONSerializer from django.utils import six from djmoney.models.fields import MoneyField - from djmoney.money import Money from djmoney.utils import get_currency_field_name @@ -29,8 +28,8 @@ def Deserializer(stream_or_string, **options): # noqa # This updated Deserializer is needed to get reversion (django-reversion) # to work in circumstances described above. - from django.core.serializers.python import \ - Deserializer as PythonDeserializer, _get_model + from django.core.serializers.python import Deserializer as PythonDeserializer + from django.core.serializers.python import _get_model ignore = options.pop("ignorenonexistent", False) diff --git a/src/ralph/lib/table/table.py b/src/ralph/lib/table/table.py index 9d8720b063..5848ffea0e 100644 --- a/src/ralph/lib/table/table.py +++ b/src/ralph/lib/table/table.py @@ -15,7 +15,7 @@ from ralph.admin.helpers import ( get_field_by_relation_path, get_field_title_by_relation_path, - getattr_dunder + getattr_dunder, ) diff --git a/src/ralph/lib/threadlocal/middleware.py b/src/ralph/lib/threadlocal/middleware.py index b61b964b32..582ac1de16 100644 --- a/src/ralph/lib/threadlocal/middleware.py +++ b/src/ralph/lib/threadlocal/middleware.py @@ -1,6 +1,5 @@ from django.utils.deprecation import MiddlewareMixin -from threadlocals.middleware import \ - ThreadLocalMiddleware as ThreadLocalMiddleware_ +from threadlocals.middleware import ThreadLocalMiddleware as ThreadLocalMiddleware_ class ThreadLocalMiddleware(ThreadLocalMiddleware_, MiddlewareMixin): diff --git a/src/ralph/lib/transitions/admin.py b/src/ralph/lib/transitions/admin.py index 4ab3607d53..d40550c285 100644 --- a/src/ralph/lib/transitions/admin.py +++ b/src/ralph/lib/transitions/admin.py @@ -14,11 +14,7 @@ from ralph.admin.views.extra import RalphDetailView from ralph.helpers import get_model_view_url_name from ralph.lib.transitions.forms import TransitionForm -from ralph.lib.transitions.models import ( - Transition, - TransitionJob, - TransitionModel -) +from ralph.lib.transitions.models import Transition, TransitionJob, TransitionModel from ralph.lib.transitions.views import RunBulkTransitionView, RunTransitionView diff --git a/src/ralph/lib/transitions/api/routers.py b/src/ralph/lib/transitions/api/routers.py index 9cad70ee13..d7f2a294d8 100644 --- a/src/ralph/lib/transitions/api/routers.py +++ b/src/ralph/lib/transitions/api/routers.py @@ -10,7 +10,7 @@ TransitionModelViewSet, TransitionsHistoryViewSet, TransitionView, - TransitionViewSet + TransitionViewSet, ) router.register(r'transitions', TransitionViewSet) diff --git a/src/ralph/lib/transitions/api/serializers.py b/src/ralph/lib/transitions/api/serializers.py index cf7ffe3ffc..b437b2376d 100644 --- a/src/ralph/lib/transitions/api/serializers.py +++ b/src/ralph/lib/transitions/api/serializers.py @@ -8,7 +8,7 @@ Transition, TransitionJob, TransitionModel, - TransitionsHistory + TransitionsHistory, ) diff --git a/src/ralph/lib/transitions/api/views.py b/src/ralph/lib/transitions/api/views.py index 9ce93c9686..2ecae10704 100644 --- a/src/ralph/lib/transitions/api/views.py +++ b/src/ralph/lib/transitions/api/views.py @@ -5,8 +5,8 @@ from django.core.exceptions import ObjectDoesNotExist from django.urls import reverse from rest_framework import serializers, status -from rest_framework.exceptions import ValidationError as DRFValidationError from rest_framework.exceptions import NotFound +from rest_framework.exceptions import ValidationError as DRFValidationError from rest_framework.response import Response from rest_framework.settings import api_settings from rest_framework.views import APIView @@ -20,20 +20,20 @@ TransitionJobSerializer, TransitionModelSerializer, TransitionSerializer, - TransitionsHistorySerializer + TransitionsHistorySerializer, ) from ralph.lib.transitions.exceptions import TransitionNotAllowedError from ralph.lib.transitions.models import ( - _check_instances_for_transition, - _transition_data_validation, Action, - run_transition, Transition, TransitionJob, TransitionModel, - TransitionsHistory + TransitionsHistory, + _check_instances_for_transition, + _transition_data_validation, + run_transition, ) -from ralph.lib.transitions.views import collect_actions, NonAtomicView +from ralph.lib.transitions.views import NonAtomicView, collect_actions FIELD_MAP = { forms.CharField: (serializers.CharField, [ diff --git a/src/ralph/lib/transitions/async.py b/src/ralph/lib/transitions/async.py index 6d849ea8bd..41c39eb1d6 100644 --- a/src/ralph/lib/transitions/async.py +++ b/src/ralph/lib/transitions/async.py @@ -11,17 +11,17 @@ FailedActionError, FreezeAsyncTransition, MoreThanOneStartedActionError, - RescheduleAsyncTransitionActionLater + RescheduleAsyncTransitionActionLater, ) from ralph.lib.transitions.models import ( + TransitionJob, + TransitionJobAction, + TransitionJobActionStatus, _check_action_with_instances, _check_instances_for_transition, _order_actions_by_requirements, _post_transition_instance_processing, _prepare_action_data, - TransitionJob, - TransitionJobAction, - TransitionJobActionStatus ) logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/transitions/checks.py b/src/ralph/lib/transitions/checks.py index 6fdf8f4b4d..843d43e328 100644 --- a/src/ralph/lib/transitions/checks.py +++ b/src/ralph/lib/transitions/checks.py @@ -2,7 +2,7 @@ from django.core.checks import Error from django.db.utils import DatabaseError -from django.template.loader import get_template, TemplateDoesNotExist +from django.template.loader import TemplateDoesNotExist, get_template logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/transitions/conf.py b/src/ralph/lib/transitions/conf.py index 90a16cae60..8cc5f3f3ee 100644 --- a/src/ralph/lib/transitions/conf.py +++ b/src/ralph/lib/transitions/conf.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from django.conf import settings - DEFAULT_ASYNC_TRANSITION_SERVICE_NAME = 'ASYNC_TRANSITIONS' TRANSITION_ATTR_TAG = 'transition_action' TRANSITION_ORIGINAL_STATUS = (0, 'Keep orginal status') diff --git a/src/ralph/lib/transitions/forms.py b/src/ralph/lib/transitions/forms.py index 220d811820..b31d50202f 100644 --- a/src/ralph/lib/transitions/forms.py +++ b/src/ralph/lib/transitions/forms.py @@ -6,10 +6,10 @@ from django.utils.translation import ugettext_lazy as _ from ralph.lib.transitions.models import ( + TRANSITION_ORIGINAL_STATUS, Action, Transition, - TRANSITION_ORIGINAL_STATUS, - TransitionModel + TransitionModel, ) TRANSITION_TEMPLATES = settings.TRANSITION_TEMPLATES diff --git a/src/ralph/lib/transitions/migrations/0001_initial.py b/src/ralph/lib/transitions/migrations/0001_initial.py index c250349075..9a247612a0 100644 --- a/src/ralph/lib/transitions/migrations/0001_initial.py +++ b/src/ralph/lib/transitions/migrations/0001_initial.py @@ -2,9 +2,9 @@ from __future__ import unicode_literals import django -from django.db import migrations, models import django_extensions.db.fields.json from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/lib/transitions/migrations/0004_auto_20160127_1119.py b/src/ralph/lib/transitions/migrations/0004_auto_20160127_1119.py index 764016e6b7..39576d2540 100644 --- a/src/ralph/lib/transitions/migrations/0004_auto_20160127_1119.py +++ b/src/ralph/lib/transitions/migrations/0004_auto_20160127_1119.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + from ralph.admin.helpers import get_content_type_for_model diff --git a/src/ralph/lib/transitions/migrations/0005_auto_20160606_1420.py b/src/ralph/lib/transitions/migrations/0005_auto_20160606_1420.py index d383ce3257..21a4b43344 100644 --- a/src/ralph/lib/transitions/migrations/0005_auto_20160606_1420.py +++ b/src/ralph/lib/transitions/migrations/0005_auto_20160606_1420.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/lib/transitions/migrations/0006_auto_20170719_1209.py b/src/ralph/lib/transitions/migrations/0006_auto_20170719_1209.py index 52b81d52b2..e736a8abb4 100644 --- a/src/ralph/lib/transitions/migrations/0006_auto_20170719_1209.py +++ b/src/ralph/lib/transitions/migrations/0006_auto_20170719_1209.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals + from zipfile import ZipFile from django.db import migrations, models diff --git a/src/ralph/lib/transitions/migrations/0009_transition_success_url.py b/src/ralph/lib/transitions/migrations/0009_transition_success_url.py index 0267ccc7de..4f2b619275 100644 --- a/src/ralph/lib/transitions/migrations/0009_transition_success_url.py +++ b/src/ralph/lib/transitions/migrations/0009_transition_success_url.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import models, migrations +from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/lib/transitions/models.py b/src/ralph/lib/transitions/models.py index 1a727a3861..aa34ef0a32 100644 --- a/src/ralph/lib/transitions/models.py +++ b/src/ralph/lib/transitions/models.py @@ -13,12 +13,7 @@ from django.core.exceptions import FieldDoesNotExist, ValidationError from django.db import models, transaction from django.db.models.base import ModelBase -from django.db.models.signals import ( - post_delete, - post_migrate, - post_save, - pre_save -) +from django.db.models.signals import post_delete, post_migrate, post_save, pre_save from django.dispatch import receiver from django.utils.functional import curry from django.utils.text import slugify @@ -26,16 +21,9 @@ from django_extensions.db.fields.json import JSONField from reversion import revisions as reversion -from ralph.admin.helpers import ( - get_content_type_for_model, - get_field_by_relation_path -) +from ralph.admin.helpers import get_content_type_for_model, get_field_by_relation_path from ralph.attachments.models import Attachment -from ralph.lib.external_services.models import ( - Job, - JOB_NOT_ENDED_STATUSES, - JobQuerySet -) +from ralph.lib.external_services.models import JOB_NOT_ENDED_STATUSES, Job, JobQuerySet from ralph.lib.metrics import statsd from ralph.lib.mixins.fields import NullableCharField from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin @@ -43,16 +31,16 @@ from ralph.lib.transitions.conf import ( DEFAULT_ASYNC_TRANSITION_SERVICE_NAME, TRANSITION_ATTR_TAG, - TRANSITION_ORIGINAL_STATUS + TRANSITION_ORIGINAL_STATUS, ) from ralph.lib.transitions.exceptions import ( TransitionModelNotFoundError, - TransitionNotAllowedError + TransitionNotAllowedError, ) from ralph.lib.transitions.fields import TransitionField from ralph.lib.transitions.utils import ( _compare_instances_types, - _sort_graph_topologically + _sort_graph_topologically, ) _transitions_fields = {} diff --git a/src/ralph/lib/transitions/tests/__init__.py b/src/ralph/lib/transitions/tests/__init__.py index 6cd7d754fa..3969b678a5 100644 --- a/src/ralph/lib/transitions/tests/__init__.py +++ b/src/ralph/lib/transitions/tests/__init__.py @@ -8,7 +8,6 @@ Transition, TransitionModel, ) - from ralph.tests.models import Order diff --git a/src/ralph/lib/transitions/tests/factories.py b/src/ralph/lib/transitions/tests/factories.py index dbb8fd5896..10fda8f78e 100644 --- a/src/ralph/lib/transitions/tests/factories.py +++ b/src/ralph/lib/transitions/tests/factories.py @@ -11,7 +11,7 @@ Transition, TransitionJob, TransitionModel, - TransitionsHistory + TransitionsHistory, ) diff --git a/src/ralph/lib/transitions/tests/test_actions.py b/src/ralph/lib/transitions/tests/test_actions.py index 72809935ea..88e82d1f89 100644 --- a/src/ralph/lib/transitions/tests/test_actions.py +++ b/src/ralph/lib/transitions/tests/test_actions.py @@ -12,14 +12,11 @@ from ralph.back_office.tests.factories import ( BackOfficeAssetFactory, OfficeInfrastructureFactory, - WarehouseFactory + WarehouseFactory, ) from ralph.lib.external_services.models import JobStatus from ralph.lib.transitions.models import TransitionJob, TransitionsHistory -from ralph.lib.transitions.tests import ( - TransitionTestCase, - TransitionTestCaseMixin -) +from ralph.lib.transitions.tests import TransitionTestCase, TransitionTestCaseMixin from ralph.licences.tests.factories import LicenceFactory diff --git a/src/ralph/lib/transitions/tests/test_async.py b/src/ralph/lib/transitions/tests/test_async.py index 0df8a5e9b4..858165287e 100644 --- a/src/ralph/lib/transitions/tests/test_async.py +++ b/src/ralph/lib/transitions/tests/test_async.py @@ -6,9 +6,9 @@ from ralph.lib.external_services.models import JobStatus from ralph.lib.transitions.models import ( - run_transition, TransitionJob, - TransitionsHistory + TransitionsHistory, + run_transition, ) from ralph.lib.transitions.tests import TransitionTestCaseMixin from ralph.tests.models import AsyncOrder, Foo, OrderStatus diff --git a/src/ralph/lib/transitions/tests/test_models.py b/src/ralph/lib/transitions/tests/test_models.py index 5907a2607b..9d86523933 100644 --- a/src/ralph/lib/transitions/tests/test_models.py +++ b/src/ralph/lib/transitions/tests/test_models.py @@ -6,14 +6,14 @@ from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.exceptions import ( TransitionModelNotFoundError, - TransitionNotAllowedError + TransitionNotAllowedError, ) from ralph.lib.transitions.models import ( + Transition, + TransitionModel, _check_and_get_transition, _create_graph_from_actions, run_field_transition, - Transition, - TransitionModel ) from ralph.lib.transitions.tests import TransitionTestCase from ralph.tests.models import Foo, Order, OrderStatus diff --git a/src/ralph/lib/transitions/tests/test_utils.py b/src/ralph/lib/transitions/tests/test_utils.py index 3ef95b8454..50f3e98f58 100644 --- a/src/ralph/lib/transitions/tests/test_utils.py +++ b/src/ralph/lib/transitions/tests/test_utils.py @@ -1,6 +1,6 @@ from django.test import TestCase -from ralph.lib.transitions.utils import _sort_graph_topologically, CycleError +from ralph.lib.transitions.utils import CycleError, _sort_graph_topologically class TopologicalSortTest(TestCase): diff --git a/src/ralph/lib/transitions/urls.py b/src/ralph/lib/transitions/urls.py index 854d461a4a..ed2718a400 100644 --- a/src/ralph/lib/transitions/urls.py +++ b/src/ralph/lib/transitions/urls.py @@ -2,7 +2,7 @@ from ralph.lib.transitions.views import ( AsyncBulkTransitionsAwaiterView, - KillTransitionJobView + KillTransitionJobView, ) urlpatterns = [ diff --git a/src/ralph/lib/transitions/views.py b/src/ralph/lib/transitions/views.py index ea071a7357..542d9a6c9e 100644 --- a/src/ralph/lib/transitions/views.py +++ b/src/ralph/lib/transitions/views.py @@ -9,7 +9,7 @@ Http404, HttpResponseBadRequest, HttpResponseForbidden, - HttpResponseRedirect + HttpResponseRedirect, ) from django.shortcuts import get_object_or_404 from django.urls import reverse @@ -27,11 +27,11 @@ from ralph.lib.permissions.views import PermissionViewMetaClass from ralph.lib.transitions.exceptions import TransitionNotAllowedError from ralph.lib.transitions.models import ( + Transition, + TransitionJob, _check_instances_for_transition, _transition_data_validation, run_transition, - Transition, - TransitionJob ) diff --git a/src/ralph/licences/migrations/0001_initial.py b/src/ralph/licences/migrations/0001_initial.py index 526529827c..a026f38088 100644 --- a/src/ralph/licences/migrations/0001_initial.py +++ b/src/ralph/licences/migrations/0001_initial.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -from django.conf import settings import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/licences/migrations/0002_auto_20151204_1325.py b/src/ralph/licences/migrations/0002_auto_20151204_1325.py index e5f4c16eee..a5aa83cbba 100644 --- a/src/ralph/licences/migrations/0002_auto_20151204_1325.py +++ b/src/ralph/licences/migrations/0002_auto_20151204_1325.py @@ -3,6 +3,7 @@ import django from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/licences/migrations/0006_auto_20200909_1115.py b/src/ralph/licences/migrations/0006_auto_20200909_1115.py index cb7989a1fa..97fe3ad5cc 100644 --- a/src/ralph/licences/migrations/0006_auto_20200909_1115.py +++ b/src/ralph/licences/migrations/0006_auto_20200909_1115.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import djmoney.models.fields from decimal import Decimal +import djmoney.models.fields +from django.db import migrations + class Migration(migrations.Migration): dependencies = [ diff --git a/src/ralph/licences/migrations/0007_auto_20240506_1633.py b/src/ralph/licences/migrations/0007_auto_20240506_1633.py index bc663e0aea..520ffdc68f 100644 --- a/src/ralph/licences/migrations/0007_auto_20240506_1633.py +++ b/src/ralph/licences/migrations/0007_auto_20240506_1633.py @@ -2,8 +2,8 @@ # Generated by Django 1.9.13 on 2024-05-06 16:33 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/licences/migrations/0008_auto_20240628_1207.py b/src/ralph/licences/migrations/0008_auto_20240628_1207.py index 9b6a192d8a..0da19b3958 100644 --- a/src/ralph/licences/migrations/0008_auto_20240628_1207.py +++ b/src/ralph/licences/migrations/0008_auto_20240628_1207.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-28 12:07 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/licences/models.py b/src/ralph/licences/models.py index 2399cfde96..c0c75e4ce6 100644 --- a/src/ralph/licences/models.py +++ b/src/ralph/licences/models.py @@ -19,7 +19,6 @@ from ralph.lib.permissions.models import PermByFieldMixin from ralph.lib.polymorphic.models import PolymorphicQuerySet - _SELECT_USED_LICENCES_QUERY = """ SELECT COALESCE(SUM({assignment_table}.{quantity_column}), 0) FROM {assignment_table} diff --git a/src/ralph/networks/fields.py b/src/ralph/networks/fields.py index 6745888d74..a96603ab17 100644 --- a/src/ralph/networks/fields.py +++ b/src/ralph/networks/fields.py @@ -3,7 +3,6 @@ from django.core.exceptions import ValidationError from django.db.models.fields import CharField - MAX_NETWORK_ADDRESS_LENGTH = 44 diff --git a/src/ralph/networks/filters.py b/src/ralph/networks/filters.py index 7bf601abaa..033d0dd7d7 100644 --- a/src/ralph/networks/filters.py +++ b/src/ralph/networks/filters.py @@ -1,13 +1,14 @@ import ipaddress import re + from django.contrib import messages from django.contrib.admin.options import IncorrectLookupParameters from django.db.models import Q from django.utils.translation import ugettext_lazy as _ from ralph.admin.filters import ( - ChoicesListFilter, SEARCH_OR_SEPARATORS_REGEX, + ChoicesListFilter, TextListFilter, ) diff --git a/src/ralph/networks/migrations/0001_initial.py b/src/ralph/networks/migrations/0001_initial.py index b86e29d64b..6cca62d52d 100644 --- a/src/ralph/networks/migrations/0001_initial.py +++ b/src/ralph/networks/migrations/0001_initial.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import django.db.models.deletion +import mptt.fields from django.db import migrations, models -import ralph.networks.fields + import ralph.lib.mixins.fields -import django.db.models.deletion -import ralph.networks.models.networks import ralph.lib.mixins.models -import mptt.fields +import ralph.networks.fields +import ralph.networks.models.networks class Migration(migrations.Migration): diff --git a/src/ralph/networks/migrations/0004_auto_20160606_1512.py b/src/ralph/networks/migrations/0004_auto_20160606_1512.py index 63b383aa30..409ccefe05 100644 --- a/src/ralph/networks/migrations/0004_auto_20160606_1512.py +++ b/src/ralph/networks/migrations/0004_auto_20160606_1512.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import datetime + +import django.db.models.deletion from django.db import migrations, models + import ralph.lib.mixins.fields -import django.db.models.deletion -import datetime class Migration(migrations.Migration): diff --git a/src/ralph/networks/migrations/0007_auto_20160804_1409.py b/src/ralph/networks/migrations/0007_auto_20160804_1409.py index 08a81780d7..1fdc12c43b 100644 --- a/src/ralph/networks/migrations/0007_auto_20160804_1409.py +++ b/src/ralph/networks/migrations/0007_auto_20160804_1409.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.networks.fields diff --git a/src/ralph/networks/migrations/0009_auto_20160823_0921.py b/src/ralph/networks/migrations/0009_auto_20160823_0921.py index 1964d201d4..3612bb0642 100644 --- a/src/ralph/networks/migrations/0009_auto_20160823_0921.py +++ b/src/ralph/networks/migrations/0009_auto_20160823_0921.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/networks/migrations/0010_auto_20170216_1230.py b/src/ralph/networks/migrations/0010_auto_20170216_1230.py index c9c32a1f39..567bb67094 100644 --- a/src/ralph/networks/migrations/0010_auto_20170216_1230.py +++ b/src/ralph/networks/migrations/0010_auto_20170216_1230.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/networks/migrations/0013_auto_20171006_0947.py b/src/ralph/networks/migrations/0013_auto_20171006_0947.py index 97a12de9b8..dcc39df7e2 100644 --- a/src/ralph/networks/migrations/0013_auto_20171006_0947.py +++ b/src/ralph/networks/migrations/0013_auto_20171006_0947.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/networks/migrations/0014_auto_20171009_1030.py b/src/ralph/networks/migrations/0014_auto_20171009_1030.py index 6852a55a70..5dd342df38 100644 --- a/src/ralph/networks/migrations/0014_auto_20171009_1030.py +++ b/src/ralph/networks/migrations/0014_auto_20171009_1030.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/networks/migrations/0015_auto_20211115_1125.py b/src/ralph/networks/migrations/0015_auto_20211115_1125.py index bdc44b7929..fc46cc7b6f 100644 --- a/src/ralph/networks/migrations/0015_auto_20211115_1125.py +++ b/src/ralph/networks/migrations/0015_auto_20211115_1125.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/networks/migrations/0016_auto_20240924_1155.py b/src/ralph/networks/migrations/0016_auto_20240924_1155.py index ef0bc00996..aa07a7a9ab 100644 --- a/src/ralph/networks/migrations/0016_auto_20240924_1155.py +++ b/src/ralph/networks/migrations/0016_auto_20240924_1155.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.polymorphic.fields diff --git a/src/ralph/networks/models/networks.py b/src/ralph/networks/models/networks.py index 979b57b4e5..17aa936057 100644 --- a/src/ralph/networks/models/networks.py +++ b/src/ralph/networks/models/networks.py @@ -106,8 +106,8 @@ class Meta: @property def HOSTNAME_MODELS(self): - from ralph.data_center.models.virtual import Cluster from ralph.data_center.models.physical import DataCenterAsset + from ralph.data_center.models.virtual import Cluster from ralph.virtual.models import VirtualServer return (DataCenterAsset, VirtualServer, Cluster, IPAddress) diff --git a/src/ralph/networks/tests/test_models.py b/src/ralph/networks/tests/test_models.py index 046662e2b9..f61a383101 100644 --- a/src/ralph/networks/tests/test_models.py +++ b/src/ralph/networks/tests/test_models.py @@ -4,7 +4,7 @@ from ddt import data, ddt, unpack from django.core.exceptions import ValidationError from django.db.models import F -from django.test import override_settings, RequestFactory +from django.test import RequestFactory, override_settings from ralph.admin.helpers import CastToInteger from ralph.assets.models import AssetLastHostname diff --git a/src/ralph/operations/changemanagement/jira.py b/src/ralph/operations/changemanagement/jira.py index 48fa452c7c..09bf46a267 100644 --- a/src/ralph/operations/changemanagement/jira.py +++ b/src/ralph/operations/changemanagement/jira.py @@ -3,7 +3,6 @@ from dateutil.parser import parse as parse_datetime - logger = logging.getLogger(__name__) diff --git a/src/ralph/operations/changemanagement/subscribtions.py b/src/ralph/operations/changemanagement/subscribtions.py index 4640d86473..69ad8b665a 100644 --- a/src/ralph/operations/changemanagement/subscribtions.py +++ b/src/ralph/operations/changemanagement/subscribtions.py @@ -10,7 +10,6 @@ from ralph.operations.changemanagement.exceptions import IgnoreOperation from ralph.operations.models import Operation, OperationStatus, OperationType - logger = logging.getLogger(__name__) diff --git a/src/ralph/operations/migrations/0001_initial.py b/src/ralph/operations/migrations/0001_initial.py index cbee8e4376..57876bbf5e 100644 --- a/src/ralph/operations/migrations/0001_initial.py +++ b/src/ralph/operations/migrations/0001_initial.py @@ -2,12 +2,13 @@ from __future__ import unicode_literals import django -from django.db import migrations, models -import ralph.lib.mixins.models import mptt.fields +import taggit.managers from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.fields -import taggit.managers +import ralph.lib.mixins.models class Migration(migrations.Migration): diff --git a/src/ralph/operations/migrations/0003_auto_20160303_1114.py b/src/ralph/operations/migrations/0003_auto_20160303_1114.py index 271cafe321..6fb7f38ef3 100644 --- a/src/ralph/operations/migrations/0003_auto_20160303_1114.py +++ b/src/ralph/operations/migrations/0003_auto_20160303_1114.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/operations/migrations/0004_auto_20160307_1138.py b/src/ralph/operations/migrations/0004_auto_20160307_1138.py index 7d9579a1cc..f40c56c7fe 100644 --- a/src/ralph/operations/migrations/0004_auto_20160307_1138.py +++ b/src/ralph/operations/migrations/0004_auto_20160307_1138.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.models diff --git a/src/ralph/operations/migrations/0005_auto_20170323_1425.py b/src/ralph/operations/migrations/0005_auto_20170323_1425.py index c0d3f385ff..af6d548e40 100644 --- a/src/ralph/operations/migrations/0005_auto_20170323_1425.py +++ b/src/ralph/operations/migrations/0005_auto_20170323_1425.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/operations/migrations/0007_auto_20170328_1728.py b/src/ralph/operations/migrations/0007_auto_20170328_1728.py index e37159fce2..44339594a4 100644 --- a/src/ralph/operations/migrations/0007_auto_20170328_1728.py +++ b/src/ralph/operations/migrations/0007_auto_20170328_1728.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations from django.conf import settings +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/operations/migrations/0008_auto_20170331_0952.py b/src/ralph/operations/migrations/0008_auto_20170331_0952.py index 599fe874f9..7e6da13c3f 100644 --- a/src/ralph/operations/migrations/0008_auto_20170331_0952.py +++ b/src/ralph/operations/migrations/0008_auto_20170331_0952.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/operations/migrations/0009_auto_20170403_1112.py b/src/ralph/operations/migrations/0009_auto_20170403_1112.py index 004766bdef..55a4108591 100644 --- a/src/ralph/operations/migrations/0009_auto_20170403_1112.py +++ b/src/ralph/operations/migrations/0009_auto_20170403_1112.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/operations/migrations/0010_auto_20170410_1031.py b/src/ralph/operations/migrations/0010_auto_20170410_1031.py index 6aec4ae28c..55fcb3ab30 100644 --- a/src/ralph/operations/migrations/0010_auto_20170410_1031.py +++ b/src/ralph/operations/migrations/0010_auto_20170410_1031.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +import django.db.models.deletion from dj.choices import Choices from django.conf import settings -import django.db.models.deletion +from django.db import migrations, models from ralph.operations.models import OperationStatus diff --git a/src/ralph/operations/migrations/0011_operation_reporter.py b/src/ralph/operations/migrations/0011_operation_reporter.py index f3249f1e46..165506b792 100644 --- a/src/ralph/operations/migrations/0011_operation_reporter.py +++ b/src/ralph/operations/migrations/0011_operation_reporter.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -from django.conf import settings import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/operations/migrations/0013_auto_20241002_1122.py b/src/ralph/operations/migrations/0013_auto_20241002_1122.py index 4304ce9b4b..be584e7043 100644 --- a/src/ralph/operations/migrations/0013_auto_20241002_1122.py +++ b/src/ralph/operations/migrations/0013_auto_20241002_1122.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.polymorphic.fields diff --git a/src/ralph/reports/management/commands/send_data_center_asset_export.py b/src/ralph/reports/management/commands/send_data_center_asset_export.py index 01a7b82ac4..2e45fe890c 100644 --- a/src/ralph/reports/management/commands/send_data_center_asset_export.py +++ b/src/ralph/reports/management/commands/send_data_center_asset_export.py @@ -8,7 +8,6 @@ from ralph.reports.resources import DataCenterAssetTextResource - logger = logging.getLogger(__name__) diff --git a/src/ralph/reports/migrations/0001_initial.py b/src/ralph/reports/migrations/0001_initial.py index f6b244bb7e..012dc946c3 100644 --- a/src/ralph/reports/migrations/0001_initial.py +++ b/src/ralph/reports/migrations/0001_initial.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.reports.models diff --git a/src/ralph/security/api.py b/src/ralph/security/api.py index 97df94014c..12ed432917 100644 --- a/src/ralph/security/api.py +++ b/src/ralph/security/api.py @@ -8,7 +8,7 @@ from ralph.api import RalphAPISerializer, RalphAPIViewSet, router from ralph.api.serializers import RalphAPISaveSerializer from ralph.networks.models.networks import IPAddress -from ralph.security.models import any_exceeded, SecurityScan, Vulnerability +from ralph.security.models import SecurityScan, Vulnerability, any_exceeded class VulnerabilitySerializer(RalphAPISerializer): diff --git a/src/ralph/security/management/commands/update_is_patched.py b/src/ralph/security/management/commands/update_is_patched.py index 468e68af68..3ff68bf2e5 100644 --- a/src/ralph/security/management/commands/update_is_patched.py +++ b/src/ralph/security/management/commands/update_is_patched.py @@ -7,7 +7,6 @@ from ralph.security.models import SecurityScan - logger = logging.getLogger(__name__) diff --git a/src/ralph/security/migrations/0001_initial.py b/src/ralph/security/migrations/0001_initial.py index c0da9d2f88..8ac1b4fba2 100644 --- a/src/ralph/security/migrations/0001_initial.py +++ b/src/ralph/security/migrations/0001_initial.py @@ -2,8 +2,8 @@ from __future__ import unicode_literals import django -from django.db import migrations, models import taggit.managers +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/security/migrations/0002_auto_20160307_1138.py b/src/ralph/security/migrations/0002_auto_20160307_1138.py index ee0dd9bc41..93f4ad47a0 100644 --- a/src/ralph/security/migrations/0002_auto_20160307_1138.py +++ b/src/ralph/security/migrations/0002_auto_20160307_1138.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.mixins.models diff --git a/src/ralph/security/transitions.py b/src/ralph/security/transitions.py index 0d59b553a6..913dc89afb 100644 --- a/src/ralph/security/transitions.py +++ b/src/ralph/security/transitions.py @@ -11,7 +11,6 @@ from ralph.lib.transitions.decorators import transition_action from ralph.virtual.models import CloudHost, VirtualServer - HOST_MODELS = [DataCenterAsset, CloudHost, VirtualServer] diff --git a/src/ralph/settings/base.py b/src/ralph/settings/base.py index 719c5a022c..8f4c6b2c27 100644 --- a/src/ralph/settings/base.py +++ b/src/ralph/settings/base.py @@ -1,15 +1,14 @@ # -*- coding: utf-8 -*- -from datetime import datetime import json import os from collections import ChainMap +from datetime import datetime from django.contrib.messages import constants as messages from moneyed import CURRENCIES from ralph.settings.hooks import HOOKS_CONFIGURATION # noqa: F401 - SILENCED_SYSTEM_CHECKS = [ "models.E006", ] # TODO fix diff --git a/src/ralph/settings/dev.py b/src/ralph/settings/dev.py index 35cf9c1c7e..65f84dbf39 100644 --- a/src/ralph/settings/dev.py +++ b/src/ralph/settings/dev.py @@ -6,14 +6,14 @@ def only_true(request): return True -DEBUG = True +DEBUG = False INSTALLED_APPS = INSTALLED_APPS + ( - "debug_toolbar", + # "debug_toolbar", "django_extensions", ) -MIDDLEWARE = MIDDLEWARE + ("debug_toolbar.middleware.DebugToolbarMiddleware",) +# MIDDLEWARE = MIDDLEWARE + ("debug_toolbar.middleware.DebugToolbarMiddleware",) DEBUG_TOOLBAR_CONFIG = { "SHOW_TOOLBAR_CALLBACK": "%s.only_true" % __name__, diff --git a/src/ralph/settings/hooks.py b/src/ralph/settings/hooks.py index 1c900c0472..825d5e3706 100644 --- a/src/ralph/settings/hooks.py +++ b/src/ralph/settings/hooks.py @@ -2,7 +2,6 @@ from ralph.lib.hooks import hook_name_to_env_name - HOOKS = ("back_office.transition_action.email_context",) HOOKS_CONFIGURATION = { hook: os.environ.get(hook_name_to_env_name(hook), "default") for hook in HOOKS diff --git a/src/ralph/sim_cards/migrations/0001_initial.py b/src/ralph/sim_cards/migrations/0001_initial.py index 1e6a13e81e..2712083a56 100644 --- a/src/ralph/sim_cards/migrations/0001_initial.py +++ b/src/ralph/sim_cards/migrations/0001_initial.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models -import ralph.lib.mixins.models +import django.core.validators import django.db.models.deletion from django.conf import settings +from django.db import migrations, models + +import ralph.lib.mixins.models import ralph.lib.transitions.fields -import django.core.validators class Migration(migrations.Migration): diff --git a/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py b/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py index 47c9b8a187..8ecf640a61 100644 --- a/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py +++ b/src/ralph/sim_cards/migrations/0002_auto_20181123_1138.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/sim_cards/migrations/0004_simcard_property_of.py b/src/ralph/sim_cards/migrations/0004_simcard_property_of.py index fba49695fb..e0b7787501 100644 --- a/src/ralph/sim_cards/migrations/0004_simcard_property_of.py +++ b/src/ralph/sim_cards/migrations/0004_simcard_property_of.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/sim_cards/models.py b/src/ralph/sim_cards/models.py index 42a642f15d..122f0cb39e 100644 --- a/src/ralph/sim_cards/models.py +++ b/src/ralph/sim_cards/models.py @@ -1,5 +1,4 @@ import datetime - from functools import partial from dj.choices import Choices @@ -16,7 +15,7 @@ from ralph.assets.models import AssetHolder from ralph.attachments.utils import send_transition_attachments_to_user -from ralph.back_office.models import autocomplete_user, Warehouse +from ralph.back_office.models import Warehouse, autocomplete_user from ralph.lib.hooks import get_hook from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin from ralph.lib.transitions.conf import get_report_name_for_transition_id diff --git a/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py b/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py index 89907fb2db..3b5daf63d8 100644 --- a/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py +++ b/src/ralph/ssl_certificates/management/commands/import_ssl_certificates.py @@ -13,7 +13,6 @@ from ralph.assets.models.assets import Manufacturer from ralph.ssl_certificates.models import CertificateType, SSLCertificate - DEFAULT_ISSUER_NAME = "CA ENT" diff --git a/src/ralph/ssl_certificates/migrations/0001_initial.py b/src/ralph/ssl_certificates/migrations/0001_initial.py index 5652075826..3b12f94855 100644 --- a/src/ralph/ssl_certificates/migrations/0001_initial.py +++ b/src/ralph/ssl_certificates/migrations/0001_initial.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +import django.db.models.deletion from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.models -import django.db.models.deletion class Migration(migrations.Migration): diff --git a/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py b/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py index 88b030d18e..817f83712d 100644 --- a/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py +++ b/src/ralph/ssl_certificates/migrations/0002_auto_20180522_1244.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py b/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py index fed493d6d7..e29d956e05 100644 --- a/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py +++ b/src/ralph/ssl_certificates/migrations/0005_auto_20200909_1012.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import djmoney.models.fields from decimal import Decimal +import djmoney.models.fields +from django.db import migrations + class Migration(migrations.Migration): dependencies = [ diff --git a/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py b/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py index c4e44142ec..c750a05454 100644 --- a/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py +++ b/src/ralph/ssl_certificates/migrations/0007_auto_20240621_1217.py @@ -1,7 +1,7 @@ # Generated by Django 2.0.13 on 2024-06-21 12:17 -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/supports/migrations/0001_initial.py b/src/ralph/supports/migrations/0001_initial.py index caf1847dd6..e52d0a4ce5 100644 --- a/src/ralph/supports/migrations/0001_initial.py +++ b/src/ralph/supports/migrations/0001_initial.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import django.db.models.deletion from django.db import migrations, models + import ralph.lib.mixins.models -import django.db.models.deletion class Migration(migrations.Migration): diff --git a/src/ralph/supports/migrations/0006_auto_20160615_0805.py b/src/ralph/supports/migrations/0006_auto_20160615_0805.py index 0c93938f17..c7e9223578 100644 --- a/src/ralph/supports/migrations/0006_auto_20160615_0805.py +++ b/src/ralph/supports/migrations/0006_auto_20160615_0805.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/supports/migrations/0008_auto_20200909_1012.py b/src/ralph/supports/migrations/0008_auto_20200909_1012.py index fadf3922ba..163eee9448 100644 --- a/src/ralph/supports/migrations/0008_auto_20200909_1012.py +++ b/src/ralph/supports/migrations/0008_auto_20200909_1012.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import djmoney.models.fields from decimal import Decimal +import djmoney.models.fields +from django.db import migrations + class Migration(migrations.Migration): dependencies = [ diff --git a/src/ralph/supports/migrations/0009_auto_20240506_1633.py b/src/ralph/supports/migrations/0009_auto_20240506_1633.py index 91128bc731..76283ca4ef 100644 --- a/src/ralph/supports/migrations/0009_auto_20240506_1633.py +++ b/src/ralph/supports/migrations/0009_auto_20240506_1633.py @@ -2,8 +2,8 @@ # Generated by Django 1.9.13 on 2024-05-06 16:33 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/supports/migrations/0010_auto_20240628_1207.py b/src/ralph/supports/migrations/0010_auto_20240628_1207.py index b8cd1f31be..d439881750 100644 --- a/src/ralph/supports/migrations/0010_auto_20240628_1207.py +++ b/src/ralph/supports/migrations/0010_auto_20240628_1207.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-28 12:07 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/supports/migrations/0010_auto_20241002_1122.py b/src/ralph/supports/migrations/0010_auto_20241002_1122.py index e039e824d9..176e992293 100644 --- a/src/ralph/supports/migrations/0010_auto_20241002_1122.py +++ b/src/ralph/supports/migrations/0010_auto_20241002_1122.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.polymorphic.fields diff --git a/src/ralph/tests/migrations/0001_initial.py b/src/ralph/tests/migrations/0001_initial.py index 07adc51723..27eaff1bea 100644 --- a/src/ralph/tests/migrations/0001_initial.py +++ b/src/ralph/tests/migrations/0001_initial.py @@ -3,8 +3,9 @@ import django from django.db import migrations, models -import ralph.lib.transitions.fields + import ralph.lib.mixins.models +import ralph.lib.transitions.fields class Migration(migrations.Migration): diff --git a/src/ralph/tests/migrations/0002_auto_20160119_0914.py b/src/ralph/tests/migrations/0002_auto_20160119_0914.py index 41087865cc..7a9aa67de6 100644 --- a/src/ralph/tests/migrations/0002_auto_20160119_0914.py +++ b/src/ralph/tests/migrations/0002_auto_20160119_0914.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/tests/migrations/0006_auto_20160607_0842.py b/src/ralph/tests/migrations/0006_auto_20160607_0842.py index 1839b792e5..2929ad830e 100644 --- a/src/ralph/tests/migrations/0006_auto_20160607_0842.py +++ b/src/ralph/tests/migrations/0006_auto_20160607_0842.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.models import ralph.lib.transitions.fields diff --git a/src/ralph/tests/migrations/0008_auto_20200909_1322.py b/src/ralph/tests/migrations/0008_auto_20200909_1322.py index be546ef105..58ec7fb16b 100644 --- a/src/ralph/tests/migrations/0008_auto_20200909_1322.py +++ b/src/ralph/tests/migrations/0008_auto_20200909_1322.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import djmoney.models.fields from decimal import Decimal +import djmoney.models.fields +from django.db import migrations + class Migration(migrations.Migration): dependencies = [ diff --git a/src/ralph/tests/migrations/0009_auto_20240621_1009.py b/src/ralph/tests/migrations/0009_auto_20240621_1009.py index a895023a3e..3441f6704b 100644 --- a/src/ralph/tests/migrations/0009_auto_20240621_1009.py +++ b/src/ralph/tests/migrations/0009_auto_20240621_1009.py @@ -2,8 +2,8 @@ # Generated by Django 1.11.8 on 2024-06-21 10:09 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/tests/migrations/0010_auto_20240621_1217.py b/src/ralph/tests/migrations/0010_auto_20240621_1217.py index 7cb1b7f60e..7e577673ee 100644 --- a/src/ralph/tests/migrations/0010_auto_20240621_1217.py +++ b/src/ralph/tests/migrations/0010_auto_20240621_1217.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-21 12:17 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/tests/migrations/0011_auto_20240621_1231.py b/src/ralph/tests/migrations/0011_auto_20240621_1231.py index eeaad488cb..96334fdcc6 100644 --- a/src/ralph/tests/migrations/0011_auto_20240621_1231.py +++ b/src/ralph/tests/migrations/0011_auto_20240621_1231.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-21 12:31 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/tests/migrations/0012_auto_20240621_1355.py b/src/ralph/tests/migrations/0012_auto_20240621_1355.py index 046a14b8be..a539759c10 100644 --- a/src/ralph/tests/migrations/0012_auto_20240621_1355.py +++ b/src/ralph/tests/migrations/0012_auto_20240621_1355.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-21 13:55 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/tests/migrations/0013_auto_20240627_1512.py b/src/ralph/tests/migrations/0013_auto_20240627_1512.py index 2a170ec393..28a5bc114c 100644 --- a/src/ralph/tests/migrations/0013_auto_20240627_1512.py +++ b/src/ralph/tests/migrations/0013_auto_20240627_1512.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-27 15:12 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/tests/migrations/0014_auto_20240628_1213.py b/src/ralph/tests/migrations/0014_auto_20240628_1213.py index d777963534..f637dce0ab 100644 --- a/src/ralph/tests/migrations/0014_auto_20240628_1213.py +++ b/src/ralph/tests/migrations/0014_auto_20240628_1213.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.13 on 2024-06-28 12:13 -from django.db import migrations import django.db.models.deletion +from django.db import migrations + import ralph.lib.mixins.fields diff --git a/src/ralph/tests/mixins.py b/src/ralph/tests/mixins.py index c6dedd3a42..3c453ea8c5 100644 --- a/src/ralph/tests/mixins.py +++ b/src/ralph/tests/mixins.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import sys from importlib import import_module, reload + from django.conf import settings from django.urls import clear_url_caches diff --git a/src/ralph/trade_marks/admin.py b/src/ralph/trade_marks/admin.py index 2fcd6454d8..5263a146c9 100644 --- a/src/ralph/trade_marks/admin.py +++ b/src/ralph/trade_marks/admin.py @@ -6,9 +6,9 @@ from ralph.admin.decorators import register from ralph.admin.filters import ( ChoicesListFilter, - custom_title_filter, DateListFilter, RelatedAutocompleteFieldListFilter, + custom_title_filter, ) from ralph.admin.mixins import RalphAdmin, RalphTabularInline from ralph.admin.views.extra import RalphDetailViewAdmin diff --git a/src/ralph/trade_marks/migrations/0001_initial.py b/src/ralph/trade_marks/migrations/0001_initial.py index fe3923c22c..a37c4350aa 100644 --- a/src/ralph/trade_marks/migrations/0001_initial.py +++ b/src/ralph/trade_marks/migrations/0001_initial.py @@ -2,9 +2,10 @@ from __future__ import unicode_literals import django +from django.conf import settings from django.db import migrations, models + import ralph.lib.mixins.models -from django.conf import settings class Migration(migrations.Migration): diff --git a/src/ralph/trade_marks/migrations/0003_trademark_image.py b/src/ralph/trade_marks/migrations/0003_trademark_image.py index 2de8c930dc..f6e6086ad7 100644 --- a/src/ralph/trade_marks/migrations/0003_trademark_image.py +++ b/src/ralph/trade_marks/migrations/0003_trademark_image.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.trade_marks.models diff --git a/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py b/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py index 9a1b8f3b5e..720dd72f1f 100644 --- a/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py +++ b/src/ralph/trade_marks/migrations/0004_auto_20190221_0923.py @@ -3,6 +3,7 @@ import django from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py b/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py index 94c719c376..8be92c3c15 100644 --- a/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py +++ b/src/ralph/trade_marks/migrations/0008_auto_20210625_0738.py @@ -2,8 +2,9 @@ from __future__ import unicode_literals import django -from django.db import migrations, models from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.models import ralph.trade_marks.models diff --git a/src/ralph/trade_marks/migrations/0011_trademarkkind.py b/src/ralph/trade_marks/migrations/0011_trademarkkind.py index 7146e45718..5e36a77c2e 100644 --- a/src/ralph/trade_marks/migrations/0011_trademarkkind.py +++ b/src/ralph/trade_marks/migrations/0011_trademarkkind.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py b/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py index a2d1418a6a..44ed442a3c 100644 --- a/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py +++ b/src/ralph/trade_marks/migrations/0013_auto_20211206_1400.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py b/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py index 910495cc5a..efc4447796 100644 --- a/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py +++ b/src/ralph/trade_marks/migrations/0014_auto_20211207_1118.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py b/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py index 53a7696d62..5c1653a5ed 100644 --- a/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py +++ b/src/ralph/trade_marks/migrations/0015_auto_20221020_1340.py @@ -2,10 +2,11 @@ from __future__ import unicode_literals import django -from django.db import migrations, models -import ralph.trade_marks.models from django.conf import settings +from django.db import migrations, models + import ralph.lib.mixins.models +import ralph.trade_marks.models class Migration(migrations.Migration): diff --git a/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py b/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py index 86a3cf7465..7993bc67d3 100644 --- a/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py +++ b/src/ralph/trade_marks/migrations/0016_auto_20240621_1217.py @@ -1,7 +1,7 @@ # Generated by Django 2.0.13 on 2024-06-21 12:17 -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/urls/dev.py b/src/ralph/urls/dev.py index f7f7c7a433..19aecacd39 100644 --- a/src/ralph/urls/dev.py +++ b/src/ralph/urls/dev.py @@ -3,9 +3,8 @@ from django.conf.urls import include, url from django.conf.urls.static import static - -from ralph.urls import urlpatterns as base_urlpatterns from ralph.urls import handler404 # noqa +from ralph.urls import urlpatterns as base_urlpatterns urlpatterns = base_urlpatterns urlpatterns += [ diff --git a/src/ralph/urls/test.py b/src/ralph/urls/test.py index 8ca218fe1c..ddafecb76c 100644 --- a/src/ralph/urls/test.py +++ b/src/ralph/urls/test.py @@ -4,10 +4,11 @@ from ralph.api.tests import api as ralph_api from ralph.lib.custom_fields.tests import urls as custom_fields_tests_urls from ralph.lib.permissions.tests import api as lib_api -from ralph.lib.permissions.tests.test_permission_view import urls as perm_view_url # noqa +from ralph.lib.permissions.tests.test_permission_view import ( + urls as perm_view_url, # noqa +) from ralph.urls.base import urlpatterns as base_urlpatterns - urlpatterns = base_urlpatterns urlpatterns += [ url(r"^", include(lib_api.urlpatterns)), diff --git a/src/ralph/virtual/api.py b/src/ralph/virtual/api.py index ce7579059b..a85df17da7 100644 --- a/src/ralph/virtual/api.py +++ b/src/ralph/virtual/api.py @@ -15,8 +15,8 @@ ServiceEnvironmentSimpleSerializer, ) from ralph.assets.api.views import ( - base_object_descendant_prefetch_related, BaseObjectViewSetMixin, + base_object_descendant_prefetch_related, ) from ralph.assets.models import Ethernet from ralph.configuration_management.api import SCMInfoSerializer diff --git a/src/ralph/virtual/management/commands/openstack_sync.py b/src/ralph/virtual/management/commands/openstack_sync.py index 26985bf95b..8160c43757 100644 --- a/src/ralph/virtual/management/commands/openstack_sync.py +++ b/src/ralph/virtual/management/commands/openstack_sync.py @@ -2,7 +2,7 @@ import logging from collections import defaultdict from datetime import datetime, timedelta -from enum import auto, Enum +from enum import Enum, auto from functools import lru_cache from django.conf import settings diff --git a/src/ralph/virtual/migrations/0002_auto_20160226_0826.py b/src/ralph/virtual/migrations/0002_auto_20160226_0826.py index ce4f0f3e31..9486fb98c0 100644 --- a/src/ralph/virtual/migrations/0002_auto_20160226_0826.py +++ b/src/ralph/virtual/migrations/0002_auto_20160226_0826.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/ralph/virtual/migrations/0003_auto_20160606_1442.py b/src/ralph/virtual/migrations/0003_auto_20160606_1442.py index c08d3c43ca..b70310f28e 100644 --- a/src/ralph/virtual/migrations/0003_auto_20160606_1442.py +++ b/src/ralph/virtual/migrations/0003_auto_20160606_1442.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import datetime + import django from django.db import migrations, models -import datetime + import ralph.lib.mixins.fields diff --git a/src/ralph/virtual/migrations/0004_virtualserver_status.py b/src/ralph/virtual/migrations/0004_virtualserver_status.py index 0308d566b4..d16a99ad4e 100644 --- a/src/ralph/virtual/migrations/0004_virtualserver_status.py +++ b/src/ralph/virtual/migrations/0004_virtualserver_status.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations + import ralph.lib.transitions.fields diff --git a/src/ralph/virtual/migrations/0007_auto_20160630_0949.py b/src/ralph/virtual/migrations/0007_auto_20160630_0949.py index 507118474c..b2323dd498 100644 --- a/src/ralph/virtual/migrations/0007_auto_20160630_0949.py +++ b/src/ralph/virtual/migrations/0007_auto_20160630_0949.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.fields diff --git a/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py b/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py index 3a35b29be0..4ec49a9329 100644 --- a/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py +++ b/src/ralph/virtual/migrations/0011_cloudprovider_client_config.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import django_extensions.db.fields.json import django_cryptography.fields +import django_extensions.db.fields.json +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/virtual/migrations/0012_cloudimage.py b/src/ralph/virtual/migrations/0012_cloudimage.py index b299e2c236..4edbcef6af 100644 --- a/src/ralph/virtual/migrations/0012_cloudimage.py +++ b/src/ralph/virtual/migrations/0012_cloudimage.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import migrations, models + import ralph.lib.mixins.models diff --git a/src/ralph/virtual/migrations/0014_auto_20240621_1009.py b/src/ralph/virtual/migrations/0014_auto_20240621_1009.py index a97e987fa2..dd8046396a 100644 --- a/src/ralph/virtual/migrations/0014_auto_20240621_1009.py +++ b/src/ralph/virtual/migrations/0014_auto_20240621_1009.py @@ -2,8 +2,8 @@ # Generated by Django 1.11.8 on 2024-06-21 10:09 from __future__ import unicode_literals -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/virtual/migrations/0015_auto_20240621_1217.py b/src/ralph/virtual/migrations/0015_auto_20240621_1217.py index bfd8ac4c5a..c4cfd14904 100644 --- a/src/ralph/virtual/migrations/0015_auto_20240621_1217.py +++ b/src/ralph/virtual/migrations/0015_auto_20240621_1217.py @@ -1,7 +1,7 @@ # Generated by Django 2.0.13 on 2024-06-21 12:17 -from django.db import migrations import django.db.models.manager +from django.db import migrations class Migration(migrations.Migration): diff --git a/src/ralph/virtual/processors/noop.py b/src/ralph/virtual/processors/noop.py index ab07a75fc6..c1d1ca2a9b 100644 --- a/src/ralph/virtual/processors/noop.py +++ b/src/ralph/virtual/processors/noop.py @@ -1,6 +1,5 @@ import logging - logger = logging.getLogger(__name__) From 0bf7a70197e9222be025bf9020d220a2819c6b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Szulc?= Date: Tue, 10 Dec 2024 11:11:53 +0100 Subject: [PATCH 10/11] Remove ruff - available only in >=python3.8 Fix flake --- requirements/code_style.txt | 1 - src/ralph/access_cards/tests/test_api.py | 5 +++- src/ralph/accessories/models.py | 1 + src/ralph/accessories/tests/factories.py | 2 +- src/ralph/accounts/api.py | 2 +- src/ralph/accounts/ldap.py | 2 +- src/ralph/accounts/models.py | 2 +- src/ralph/accounts/tests/tests.py | 12 +++++++--- src/ralph/accounts/urls.py | 2 +- src/ralph/accounts/views.py | 6 ++--- src/ralph/admin/autocomplete.py | 2 +- src/ralph/admin/decorators.py | 7 +++++- src/ralph/admin/m2m.py | 4 ++-- src/ralph/admin/mixins.py | 2 +- src/ralph/admin/sitetrees.py | 2 +- .../admin/templatetags/dashboard_tags.py | 9 +++++-- src/ralph/admin/templatetags/ralph_tags.py | 2 +- src/ralph/admin/tests/test_templatetags.py | 2 +- src/ralph/admin/tests/tests_filters.py | 16 +++++++++---- src/ralph/admin/tests/tests_helpers.py | 2 +- src/ralph/admin/views/extra.py | 4 ++-- src/ralph/admin/views/main.py | 2 +- src/ralph/admin/views/multiadd.py | 2 +- src/ralph/api/fields.py | 7 +++++- src/ralph/api/permissions.py | 2 +- src/ralph/api/serializers.py | 12 ++++++---- src/ralph/api/tests/_base.py | 2 +- src/ralph/api/tests/test_filters.py | 11 ++++++--- src/ralph/api/tests/test_viewsets.py | 2 +- src/ralph/api/viewsets.py | 7 ++++-- src/ralph/assets/admin.py | 9 ++++--- src/ralph/assets/api/routers.py | 2 +- src/ralph/assets/api/serializers.py | 6 ++--- src/ralph/assets/api/serializers_dchosts.py | 2 +- src/ralph/assets/models/assets.py | 17 +++++++++---- src/ralph/assets/models/base.py | 7 ++++-- src/ralph/assets/models/components.py | 8 +++++-- src/ralph/assets/models/configuration.py | 5 +++- src/ralph/assets/signals.py | 2 +- src/ralph/assets/subscribers.py | 2 +- src/ralph/assets/tests/factories.py | 9 ++++--- src/ralph/assets/tests/test_api.py | 19 +++++++++------ src/ralph/assets/tests/test_models.py | 2 +- src/ralph/assets/tests/test_signals.py | 4 ++-- src/ralph/assets/tests/test_subscribers.py | 5 +++- src/ralph/assets/views.py | 2 +- src/ralph/back_office/admin.py | 12 ++++++++-- src/ralph/back_office/api.py | 6 ++++- src/ralph/back_office/models.py | 8 +++++-- src/ralph/back_office/tests/factories.py | 8 +++++-- src/ralph/back_office/tests/test_api.py | 7 ++++-- src/ralph/back_office/tests/test_models.py | 14 +++++------ src/ralph/configuration_management/views.py | 1 - src/ralph/dashboards/api/views.py | 5 +++- src/ralph/dashboards/models.py | 6 ++++- src/ralph/dashboards/tests/test_parser.py | 7 ++++-- src/ralph/data_center/admin.py | 12 +++++----- src/ralph/data_center/api/routers.py | 2 +- src/ralph/data_center/api/serializers.py | 4 ++-- src/ralph/data_center/api/views.py | 8 +++---- src/ralph/data_center/models/physical.py | 10 +++++--- src/ralph/data_center/models/virtual.py | 7 ++++-- src/ralph/data_center/subscribers.py | 2 +- src/ralph/data_center/tests/factories.py | 10 ++++---- src/ralph/data_center/tests/test_admin.py | 14 +++++++---- src/ralph/data_center/tests/test_api.py | 6 ++--- src/ralph/data_center/tests/test_forms.py | 5 +++- src/ralph/data_center/tests/test_models.py | 6 ++--- src/ralph/data_center/tests/test_signals.py | 5 +++- .../data_center/tests/test_subscribers.py | 6 ++--- src/ralph/data_center/tests/test_view.py | 9 ++++--- .../commands/create_preboot_configuration.py | 6 ++++- .../commands/create_server_model.py | 7 +++++- .../management/commands/demodata.py | 17 +++++++------ .../management/commands/import_attachments.py | 5 +++- .../management/commands/initial_data.py | 17 ++++++------- src/ralph/data_importer/mixins.py | 2 +- src/ralph/data_importer/resources.py | 17 +++++++++---- .../data_importer/tests/test_commands.py | 10 +++++--- src/ralph/data_importer/tests/test_export.py | 4 ++-- src/ralph/data_importer/tests/test_fields.py | 5 +++- src/ralph/data_importer/tests/test_widgets.py | 7 ++++-- .../dc_view/serializers/models_serializer.py | 2 +- src/ralph/dc_view/tests.py | 9 ++++--- src/ralph/dc_view/views/api.py | 2 +- src/ralph/deployment/admin.py | 2 +- src/ralph/deployment/deployment.py | 2 +- src/ralph/deployment/mixins.py | 5 +++- src/ralph/deployment/tests/test_deployment.py | 11 +++++---- .../deployment/tests/test_transitions.py | 7 ++++-- src/ralph/deployment/urls.py | 8 ++++++- src/ralph/dhcp/admin.py | 7 +++++- src/ralph/dhcp/tests/factories.py | 7 +++++- src/ralph/dhcp/tests/test_agent.py | 2 +- src/ralph/dhcp/views.py | 8 +++++-- src/ralph/dns/tests.py | 13 +++++++--- src/ralph/domains/admin.py | 2 +- src/ralph/domains/models/domains.py | 2 +- src/ralph/domains/tests/factories.py | 2 +- src/ralph/helpers.py | 2 +- src/ralph/lib/custom_fields/admin.py | 2 +- .../lib/custom_fields/api/serializers.py | 2 +- src/ralph/lib/custom_fields/api/viewsets.py | 5 +++- src/ralph/lib/custom_fields/fields.py | 2 +- src/ralph/lib/custom_fields/forms.py | 2 +- src/ralph/lib/custom_fields/models.py | 5 +++- src/ralph/lib/custom_fields/tests/api.py | 2 +- .../lib/custom_fields/tests/factories.py | 2 +- src/ralph/lib/hooks/main.py | 2 +- src/ralph/lib/metrics/collector.py | 2 +- src/ralph/lib/metrics/middlewares.py | 2 +- src/ralph/lib/mixins/tests/test_api.py | 2 +- src/ralph/lib/permissions/admin.py | 5 +++- src/ralph/lib/permissions/api.py | 5 +++- src/ralph/lib/permissions/tests/api.py | 9 +++++-- src/ralph/lib/permissions/tests/models.py | 2 +- .../tests/test_permissions_per_object.py | 4 ++-- src/ralph/lib/polymorphic/models.py | 2 +- .../lib/polymorphic/tests/tests_models.py | 2 +- src/ralph/lib/table/table.py | 2 +- src/ralph/lib/threadlocal/middleware.py | 3 ++- src/ralph/lib/transitions/admin.py | 6 ++++- src/ralph/lib/transitions/api/routers.py | 2 +- src/ralph/lib/transitions/api/serializers.py | 2 +- src/ralph/lib/transitions/api/views.py | 14 +++++------ src/ralph/lib/transitions/async.py | 10 ++++---- src/ralph/lib/transitions/checks.py | 2 +- src/ralph/lib/transitions/forms.py | 4 ++-- src/ralph/lib/transitions/models.py | 24 ++++++++++++++----- .../templatetags/transitions_tags.py | 2 +- src/ralph/lib/transitions/tests/factories.py | 2 +- .../lib/transitions/tests/test_actions.py | 7 ++++-- src/ralph/lib/transitions/tests/test_async.py | 4 ++-- .../lib/transitions/tests/test_models.py | 6 ++--- src/ralph/lib/transitions/tests/test_utils.py | 2 +- src/ralph/lib/transitions/urls.py | 2 +- src/ralph/lib/transitions/views.py | 6 ++--- src/ralph/licences/admin.py | 8 +++++-- src/ralph/licences/api.py | 4 ++-- src/ralph/licences/models.py | 7 +++++- src/ralph/licences/tests/factories.py | 6 ++--- src/ralph/networks/admin.py | 12 +++++----- src/ralph/networks/api.py | 7 +++++- src/ralph/networks/filters.py | 4 ++-- src/ralph/networks/models/networks.py | 7 ++++-- src/ralph/networks/tests/factories.py | 2 +- src/ralph/networks/tests/test_forms.py | 2 +- src/ralph/networks/tests/test_models.py | 6 ++--- src/ralph/notifications/test_notification.py | 5 +++- src/ralph/operations/admin.py | 2 +- src/ralph/operations/changemanagement/jira.py | 2 +- src/ralph/operations/models.py | 6 ++++- src/ralph/operations/tests/factories.py | 2 +- src/ralph/reports/helpers.py | 7 ++++-- src/ralph/reports/models.py | 6 ++++- src/ralph/reports/resources.py | 6 ++++- src/ralph/reports/tests/test_reports.py | 6 ++--- src/ralph/reports/tests/test_resources.py | 10 ++++++-- src/ralph/security/api.py | 2 +- src/ralph/security/models.py | 6 ++++- src/ralph/security/tests/test_api.py | 5 +++- src/ralph/security/tests/test_serializers.py | 5 +++- src/ralph/settings/prod.py | 4 ++-- src/ralph/sim_cards/admin.py | 6 ++++- src/ralph/sim_cards/models.py | 10 +++++--- src/ralph/sim_cards/tests/test_admin.py | 2 +- src/ralph/ssl_certificates/tests/factories.py | 5 +++- src/ralph/supports/admin.py | 6 ++++- src/ralph/supports/api.py | 2 +- src/ralph/supports/models.py | 6 ++++- src/ralph/supports/tests/factories.py | 2 +- src/ralph/tests/admin.py | 2 +- src/ralph/tests/models.py | 2 +- src/ralph/trade_marks/admin.py | 8 +++---- src/ralph/trade_marks/models.py | 6 ++++- src/ralph/trade_marks/tests/factories.py | 2 +- src/ralph/urls/dev.py | 2 +- src/ralph/urls/test.py | 5 ++-- src/ralph/virtual/admin.py | 4 ++-- src/ralph/virtual/api.py | 6 ++--- src/ralph/virtual/cloudsync.py | 6 ++++- .../management/commands/openstack_sync.py | 11 ++++++--- src/ralph/virtual/models.py | 7 ++++-- src/ralph/virtual/tests/factories.py | 4 ++-- src/ralph/virtual/tests/test_admin.py | 2 +- src/ralph/virtual/tests/test_api.py | 11 +++++---- src/ralph/virtual/tests/test_models.py | 11 +++++---- .../virtual/tests/test_openstack_sync.py | 6 ++--- 188 files changed, 681 insertions(+), 356 deletions(-) diff --git a/requirements/code_style.txt b/requirements/code_style.txt index 7b4f415bf2..a261921910 100644 --- a/requirements/code_style.txt +++ b/requirements/code_style.txt @@ -1,4 +1,3 @@ flake8==3.7.9 isort==4.2.5 pyflakes==1.5.0 -ruff==0.8.2 diff --git a/src/ralph/access_cards/tests/test_api.py b/src/ralph/access_cards/tests/test_api.py index 4906f5ec81..d99b3a1a4a 100644 --- a/src/ralph/access_cards/tests/test_api.py +++ b/src/ralph/access_cards/tests/test_api.py @@ -3,7 +3,10 @@ from rest_framework import status from rest_framework.reverse import reverse -from ralph.access_cards.tests.factories import AccessCardFactory, AccessZoneFactory +from ralph.access_cards.tests.factories import ( + AccessCardFactory, + AccessZoneFactory +) from ralph.accounts.tests.factories import RegionFactory from ralph.api.tests._base import RalphAPITestCase from ralph.tests.factories import UserFactory diff --git a/src/ralph/accessories/models.py b/src/ralph/accessories/models.py index b14202acaf..eaa55ce589 100644 --- a/src/ralph/accessories/models.py +++ b/src/ralph/accessories/models.py @@ -18,6 +18,7 @@ from ralph.lib.transitions.fields import TransitionField from ralph.lib.transitions.models import TransitionWorkflowBaseWithPermissions + _SELECT_USED_ACCESSORY_QUERY = """ SELECT COALESCE(SUM({assignment_table}.{quantity_column}), 0) FROM {assignment_table} diff --git a/src/ralph/accessories/tests/factories.py b/src/ralph/accessories/tests/factories.py index 4df6b0e9fc..81fe925c2f 100644 --- a/src/ralph/accessories/tests/factories.py +++ b/src/ralph/accessories/tests/factories.py @@ -1,4 +1,4 @@ -from factory import Sequence, SubFactory, post_generation +from factory import post_generation, Sequence, SubFactory from factory.django import DjangoModelFactory from ralph.accessories.models import Accessory, AccessoryStatus, AccessoryUser diff --git a/src/ralph/accounts/api.py b/src/ralph/accounts/api.py index 57513f6572..b566399325 100644 --- a/src/ralph/accounts/api.py +++ b/src/ralph/accounts/api.py @@ -8,7 +8,7 @@ from ralph.api.permissions import IsSuperuserOrReadonly from ralph.back_office.api import ( BackOfficeAssetSimpleSerializer, - BackOfficeAssetViewSet, + BackOfficeAssetViewSet ) from ralph.back_office.models import BackOfficeAsset from ralph.licences.api import LicenceUserViewSet diff --git a/src/ralph/accounts/ldap.py b/src/ralph/accounts/ldap.py index 74d090d254..efa9b50f56 100644 --- a/src/ralph/accounts/ldap.py +++ b/src/ralph/accounts/ldap.py @@ -6,7 +6,7 @@ from django.contrib.auth.models import Group from django.dispatch import receiver from django.utils.encoding import force_text -from django_auth_ldap.backend import LDAPSettings, _LDAPUser, populate_user +from django_auth_ldap.backend import _LDAPUser, LDAPSettings, populate_user logger = logging.getLogger(__name__) diff --git a/src/ralph/accounts/models.py b/src/ralph/accounts/models.py index 1e2e262ce8..2646dacf7c 100644 --- a/src/ralph/accounts/models.py +++ b/src/ralph/accounts/models.py @@ -16,7 +16,7 @@ from ralph.lib.permissions.models import ( PermByFieldMixin, PermissionsForObjectMixin, - user_permission, + user_permission ) diff --git a/src/ralph/accounts/tests/tests.py b/src/ralph/accounts/tests/tests.py index 9e1bb9f641..76eaeef62e 100644 --- a/src/ralph/accounts/tests/tests.py +++ b/src/ralph/accounts/tests/tests.py @@ -10,14 +10,20 @@ from rest_framework import status from ralph.accounts.ldap import manager_country_attribute_populate -from ralph.accounts.management.commands.ldap_sync import _truncate, ldap_module_exists +from ralph.accounts.management.commands.ldap_sync import ( + _truncate, + ldap_module_exists +) from ralph.accounts.models import RalphUser, Region from ralph.api.tests._base import RalphAPITestCase from ralph.assets.tests.factories import ( BackOfficeAssetModelFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory +) +from ralph.back_office.tests.factories import ( + BackOfficeAssetFactory, + WarehouseFactory ) -from ralph.back_office.tests.factories import BackOfficeAssetFactory, WarehouseFactory from ralph.licences.models import LicenceUser from ralph.licences.tests.factories import LicenceFactory from ralph.tests import factories diff --git a/src/ralph/accounts/urls.py b/src/ralph/accounts/urls.py index 4b5c5441ef..9e5e26cedd 100644 --- a/src/ralph/accounts/urls.py +++ b/src/ralph/accounts/urls.py @@ -5,7 +5,7 @@ CurrentUserInfoView, InventoryTagConfirmationView, InventoryTagView, - UserProfileView, + UserProfileView ) urlpatterns = [ diff --git a/src/ralph/accounts/views.py b/src/ralph/accounts/views.py index e3920f034e..8a1cc387f9 100644 --- a/src/ralph/accounts/views.py +++ b/src/ralph/accounts/views.py @@ -14,17 +14,17 @@ AssetList, AssignedLicenceList, AssignedSimcardsList, - UserInfoMixin, + UserInfoMixin ) from ralph.accounts.helpers import ( ACCEPTANCE_LOAN_TRANSITION_ID, - ACCEPTANCE_TRANSITION_ID, acceptance_transition_exists, + ACCEPTANCE_TRANSITION_ID, get_acceptance_url, get_assets_to_accept, get_assets_to_accept_loan, get_loan_acceptance_url, - loan_transition_exists, + loan_transition_exists ) from ralph.admin.mixins import RalphBaseTemplateView, RalphTemplateView from ralph.back_office.models import BackOfficeAsset diff --git a/src/ralph/admin/autocomplete.py b/src/ralph/admin/autocomplete.py index f8e280c887..ef64e3fadd 100644 --- a/src/ralph/admin/autocomplete.py +++ b/src/ralph/admin/autocomplete.py @@ -14,7 +14,7 @@ from ralph.admin.helpers import ( get_admin_url, get_field_by_relation_path, - get_value_by_relation_path, + get_value_by_relation_path ) from ralph.admin.sites import ralph_site from ralph.lib.permissions.models import PermissionsForObjectMixin diff --git a/src/ralph/admin/decorators.py b/src/ralph/admin/decorators.py index 3bde3ca665..f8e54b16f9 100644 --- a/src/ralph/admin/decorators.py +++ b/src/ralph/admin/decorators.py @@ -6,7 +6,12 @@ from django.db.models import Model from ralph.admin.sites import ralph_site -from ralph.admin.views.extra import CHANGE, LIST, VIEW_TYPES, RalphExtraViewMixin +from ralph.admin.views.extra import ( + CHANGE, + LIST, + RalphExtraViewMixin, + VIEW_TYPES +) register = partial(django_register, site=ralph_site) diff --git a/src/ralph/admin/m2m.py b/src/ralph/admin/m2m.py index 2b2e4c7c70..6174b26007 100644 --- a/src/ralph/admin/m2m.py +++ b/src/ralph/admin/m2m.py @@ -43,7 +43,7 @@ class AuthorAdmin(admin.ModelAdmin): from functools import partial from django import forms -from django.contrib.admin.utils import NestedObjects, flatten_fieldsets +from django.contrib.admin.utils import flatten_fieldsets, NestedObjects from django.core.exceptions import ValidationError from django.db import router from django.db.models import ForeignKey @@ -51,7 +51,7 @@ class AuthorAdmin(admin.ModelAdmin): from django.forms.models import ( BaseInlineFormSet, modelform_defines_fields, - modelformset_factory, + modelformset_factory ) from django.utils.text import get_text_list from django.utils.translation import gettext_lazy as _ diff --git a/src/ralph/admin/mixins.py b/src/ralph/admin/mixins.py index 1d610ab7ce..94d092c4ec 100644 --- a/src/ralph/admin/mixins.py +++ b/src/ralph/admin/mixins.py @@ -34,7 +34,7 @@ from ralph.lib.mixins.models import AdminAbsoluteUrlMixin from ralph.lib.permissions.admin import ( PermissionAdminMixin, - PermissionsPerObjectFormMixin, + PermissionsPerObjectFormMixin ) from ralph.lib.permissions.models import PermByFieldMixin from ralph.lib.permissions.views import PermissionViewMetaClass diff --git a/src/ralph/admin/sitetrees.py b/src/ralph/admin/sitetrees.py index a3717934c9..f5b0a0f15c 100644 --- a/src/ralph/admin/sitetrees.py +++ b/src/ralph/admin/sitetrees.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from django.apps import apps from django.conf import settings -from django.utils.translation import activate from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import activate from sitetree.sitetreeapp import register_i18n_trees from sitetree.utils import item, tree diff --git a/src/ralph/admin/templatetags/dashboard_tags.py b/src/ralph/admin/templatetags/dashboard_tags.py index fa92384236..bff4b958dc 100644 --- a/src/ralph/admin/templatetags/dashboard_tags.py +++ b/src/ralph/admin/templatetags/dashboard_tags.py @@ -24,11 +24,16 @@ get_team_asset_acceptance_url, get_team_assets_to_accept, get_test_asset_acceptance_url, - get_test_assets_to_accept, + get_test_assets_to_accept ) from ralph.assets.models import BaseObject, Service, ServiceEnvironment from ralph.back_office.models import BackOfficeAsset -from ralph.data_center.models import DataCenter, DataCenterAsset, Rack, RackAccessory +from ralph.data_center.models import ( + DataCenter, + DataCenterAsset, + Rack, + RackAccessory +) register = Library() COLORS = ["green", "blue", "purple", "orange", "red", "pink"] diff --git a/src/ralph/admin/templatetags/ralph_tags.py b/src/ralph/admin/templatetags/ralph_tags.py index e22d2949c8..5deb9da2be 100644 --- a/src/ralph/admin/templatetags/ralph_tags.py +++ b/src/ralph/admin/templatetags/ralph_tags.py @@ -6,7 +6,7 @@ from ralph.admin.helpers import ( get_content_type_for_model, get_field_by_relation_path, - get_value_by_relation_path, + get_value_by_relation_path ) from ralph.lib.transitions.models import TransitionsHistory diff --git a/src/ralph/admin/tests/test_templatetags.py b/src/ralph/admin/tests/test_templatetags.py index 3e8cacf0b3..6d99558976 100644 --- a/src/ralph/admin/tests/test_templatetags.py +++ b/src/ralph/admin/tests/test_templatetags.py @@ -7,7 +7,7 @@ get_user_equipment_to_accept_loan_tile_data, get_user_equipment_to_accept_return_tile_data, get_user_equipment_to_accept_tile_data, - get_user_simcard_to_accept_tile_data, + get_user_simcard_to_accept_tile_data ) diff --git a/src/ralph/admin/tests/tests_filters.py b/src/ralph/admin/tests/tests_filters.py index 45d37a2207..5917d77f21 100644 --- a/src/ralph/admin/tests/tests_filters.py +++ b/src/ralph/admin/tests/tests_filters.py @@ -10,6 +10,7 @@ from ralph.admin.filters import ( BooleanListFilter, ChoicesListFilter, + date_format_to_human, DateListFilter, IPFilter, LiquidatedStatusFilter, @@ -18,17 +19,22 @@ RelatedFieldListFilter, TagsListFilter, TextListFilter, - TreeRelatedAutocompleteFilterWithDescendants, - date_format_to_human, + TreeRelatedAutocompleteFilterWithDescendants ) from ralph.admin.sites import ralph_site from ralph.assets.tests.factories import ( ConfigurationClassFactory, - ConfigurationModuleFactory, + ConfigurationModuleFactory ) from ralph.data_center.admin import DataCenterAssetAdmin -from ralph.data_center.models.physical import DataCenterAsset, DataCenterAssetStatus -from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory +from ralph.data_center.models.physical import ( + DataCenterAsset, + DataCenterAssetStatus +) +from ralph.data_center.tests.factories import ( + DataCenterAssetFactory, + RackFactory +) from ralph.supports.admin import SupportAdmin from ralph.supports.models import Support from ralph.supports.tests.factories import SupportFactory diff --git a/src/ralph/admin/tests/tests_helpers.py b/src/ralph/admin/tests/tests_helpers.py index 4ec3352057..f7492ee30a 100644 --- a/src/ralph/admin/tests/tests_helpers.py +++ b/src/ralph/admin/tests/tests_helpers.py @@ -8,7 +8,7 @@ generate_html_link, get_content_type_for_model, get_field_by_relation_path, - getattr_dunder, + getattr_dunder ) from ralph.assets.models.assets import Asset, Manufacturer from ralph.assets.models.base import BaseObject diff --git a/src/ralph/admin/views/extra.py b/src/ralph/admin/views/extra.py index 7675a32030..06cf4f6e48 100644 --- a/src/ralph/admin/views/extra.py +++ b/src/ralph/admin/views/extra.py @@ -6,10 +6,10 @@ from django.shortcuts import get_object_or_404 from ralph.admin.mixins import ( - RalphAdmin, - RalphTemplateView, get_inline_media, initialize_search_form, + RalphAdmin, + RalphTemplateView ) from ralph.admin.sites import ralph_site from ralph.helpers import get_model_view_url_name diff --git a/src/ralph/admin/views/main.py b/src/ralph/admin/views/main.py index f38b8abb74..5ed30c923e 100644 --- a/src/ralph/admin/views/main.py +++ b/src/ralph/admin/views/main.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from django.contrib.admin.views.main import SEARCH_VAR, ChangeList +from django.contrib.admin.views.main import ChangeList, SEARCH_VAR SEARCH_SCOPE_VAR = "search-scope" BULK_EDIT_VAR = "bulk_edit" diff --git a/src/ralph/admin/views/multiadd.py b/src/ralph/admin/views/multiadd.py index 8fd5a0c30e..7a9cf2d579 100644 --- a/src/ralph/admin/views/multiadd.py +++ b/src/ralph/admin/views/multiadd.py @@ -13,7 +13,7 @@ from ralph.admin.fields import ( IntegerMultilineField, MultilineField, - MultivalueFormMixin, + MultivalueFormMixin ) from ralph.admin.mixins import RalphTemplateView from ralph.admin.sites import ralph_site diff --git a/src/ralph/api/fields.py b/src/ralph/api/fields.py index 2d25dbf3d1..beab017a28 100644 --- a/src/ralph/api/fields.py +++ b/src/ralph/api/fields.py @@ -1,6 +1,11 @@ from collections import OrderedDict -from rest_framework.fields import ChoiceField, Field, MultipleChoiceField, ReadOnlyField +from rest_framework.fields import ( + ChoiceField, + Field, + MultipleChoiceField, + ReadOnlyField +) class StrField(Field): diff --git a/src/ralph/api/permissions.py b/src/ralph/api/permissions.py index 789eafdd88..754d76690d 100644 --- a/src/ralph/api/permissions.py +++ b/src/ralph/api/permissions.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from rest_framework.permissions import SAFE_METHODS, BasePermission +from rest_framework.permissions import BasePermission, SAFE_METHODS class IsSuperuserOrReadonly(BasePermission): diff --git a/src/ralph/api/serializers.py b/src/ralph/api/serializers.py index 0f68daee98..ce8cedff49 100644 --- a/src/ralph/api/serializers.py +++ b/src/ralph/api/serializers.py @@ -3,24 +3,28 @@ import operator from functools import reduce -from django.core.exceptions import NON_FIELD_ERRORS, ObjectDoesNotExist from django.core.exceptions import ValidationError as DjangoValidationError +from django.core.exceptions import NON_FIELD_ERRORS, ObjectDoesNotExist from django.db import transaction from django.db.models import Q from django.db.models.fields import exceptions from rest_framework import permissions, relations, serializers -from rest_framework.exceptions import ValidationError as RestFrameworkValidationError +from rest_framework.exceptions import \ + ValidationError as RestFrameworkValidationError from rest_framework.settings import api_settings from rest_framework.utils import model_meta from reversion import revisions as reversion -from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField +from taggit_serializer.serializers import ( + TaggitSerializer, + TagListSerializerField +) from ralph.api.fields import AbsoluteUrlField, ReversedChoiceField from ralph.api.relations import RalphHyperlinkedRelatedField, RalphRelatedField from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TaggableMixin from ralph.lib.permissions.api import ( PermissionsPerFieldSerializerMixin, - RelatedObjectsPermissionsSerializerMixin, + RelatedObjectsPermissionsSerializerMixin ) logger = logging.getLogger(__name__) diff --git a/src/ralph/api/tests/_base.py b/src/ralph/api/tests/_base.py index ce3ed19f14..b8cda55bd3 100644 --- a/src/ralph/api/tests/_base.py +++ b/src/ralph/api/tests/_base.py @@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType -from django.db import DEFAULT_DB_ALIAS, connections +from django.db import connections, DEFAULT_DB_ALIAS from django.test.utils import CaptureQueriesContext # noqa from rest_framework.test import APITestCase diff --git a/src/ralph/api/tests/test_filters.py b/src/ralph/api/tests/test_filters.py index 71b70ce3bd..244487850a 100644 --- a/src/ralph/api/tests/test_filters.py +++ b/src/ralph/api/tests/test_filters.py @@ -8,12 +8,17 @@ from rest_framework.test import APIClient, APIRequestFactory from ralph.api.filters import ( - FALSE_VALUES, - TRUE_VALUES, ExtendedFiltersBackend, + FALSE_VALUES, LookupFilterBackend, + TRUE_VALUES +) +from ralph.api.tests.api import ( + Bar, + BarViewSet, + ManufacturerViewSet, + TestManufacturer ) -from ralph.api.tests.api import Bar, BarViewSet, ManufacturerViewSet, TestManufacturer from ralph.tests import RalphTestCase from ralph.tests.factories import TestManufacturerFactory diff --git a/src/ralph/api/tests/test_viewsets.py b/src/ralph/api/tests/test_viewsets.py index d6b83ea844..0a1fb50afb 100644 --- a/src/ralph/api/tests/test_viewsets.py +++ b/src/ralph/api/tests/test_viewsets.py @@ -10,7 +10,7 @@ CarSerializer, CarViewSet, ManufacturerSerializer2, - ManufacturerViewSet, + ManufacturerViewSet ) from ralph.api.viewsets import RalphAPIViewSet from ralph.tests import RalphTestCase diff --git a/src/ralph/api/viewsets.py b/src/ralph/api/viewsets.py index a6b1229f68..c3fe60b655 100644 --- a/src/ralph/api/viewsets.py +++ b/src/ralph/api/viewsets.py @@ -12,12 +12,15 @@ ImportedIdFilterBackend, LookupFilterBackend, PolymorphicDescendantsFilterBackend, - TagsFilterBackend, + TagsFilterBackend ) from ralph.api.serializers import RalphAPISaveSerializer, ReversedChoiceField from ralph.api.utils import QuerysetRelatedMixin from ralph.lib.custom_fields.api import CustomFieldsFilterBackend -from ralph.lib.permissions.api import PermissionsForObjectFilter, RalphPermission +from ralph.lib.permissions.api import ( + PermissionsForObjectFilter, + RalphPermission +) class AdminSearchFieldsMixin(object): diff --git a/src/ralph/assets/admin.py b/src/ralph/assets/admin.py index f62fdbe629..2ded3adcc8 100644 --- a/src/ralph/assets/admin.py +++ b/src/ralph/assets/admin.py @@ -19,7 +19,7 @@ ManufacturerKind, ProfitCenter, Service, - ServiceEnvironment, + ServiceEnvironment ) from ralph.assets.models.base import BaseObject from ralph.assets.models.components import ( @@ -29,9 +29,12 @@ FibreChannelCard, GenericComponent, Memory, - Processor, + Processor +) +from ralph.assets.models.configuration import ( + ConfigurationClass, + ConfigurationModule ) -from ralph.assets.models.configuration import ConfigurationClass, ConfigurationModule from ralph.data_importer import resources from ralph.lib.custom_fields.admin import CustomFieldValueAdminMixin from ralph.lib.table.table import Table, TableWithUrl diff --git a/src/ralph/assets/api/routers.py b/src/ralph/assets/api/routers.py index 363a80a4b7..24d7b7aed1 100644 --- a/src/ralph/assets/api/routers.py +++ b/src/ralph/assets/api/routers.py @@ -19,7 +19,7 @@ ProcessorViewSet, ProfitCenterViewSet, ServiceEnvironmentViewSet, - ServiceViewSet, + ServiceViewSet ) router.register(r"assetholders", AssetHolderViewSet) diff --git a/src/ralph/assets/api/serializers.py b/src/ralph/assets/api/serializers.py index 9b5d9429d4..1a7d03980b 100644 --- a/src/ralph/assets/api/serializers.py +++ b/src/ralph/assets/api/serializers.py @@ -9,7 +9,7 @@ from ralph.api.serializers import ( AdditionalLookupRelatedField, RalphAPISaveSerializer, - ReversionHistoryAPISerializerMixin, + ReversionHistoryAPISerializerMixin ) from ralph.api.utils import PolymorphicSerializer from ralph.assets.models import ( @@ -27,14 +27,14 @@ ManufacturerKind, ProfitCenter, Service, - ServiceEnvironment, + ServiceEnvironment ) from ralph.assets.models.components import ( Disk, Ethernet, FibreChannelCard, Memory, - Processor, + Processor ) from ralph.configuration_management.api import SCMInfoSerializer from ralph.lib.custom_fields.api import WithCustomFieldsSerializerMixin diff --git a/src/ralph/assets/api/serializers_dchosts.py b/src/ralph/assets/api/serializers_dchosts.py index 70636c5ff3..839c42ee1c 100644 --- a/src/ralph/assets/api/serializers_dchosts.py +++ b/src/ralph/assets/api/serializers_dchosts.py @@ -3,7 +3,7 @@ from ralph.assets.api.serializers import ( BaseObjectSerializer, ComponentSerializerMixin, - SecurityScanField, + SecurityScanField ) from ralph.assets.models import BaseObject from ralph.data_center.api.serializers import DataCenterAssetSimpleSerializer diff --git a/src/ralph/assets/models/assets.py b/src/ralph/assets/models/assets.py index a716d79e34..511783accb 100644 --- a/src/ralph/assets/models/assets.py +++ b/src/ralph/assets/models/assets.py @@ -13,14 +13,23 @@ from ralph.accounts.models import Team from ralph.admin.autocomplete import AutocompleteTooltipMixin from ralph.assets.models.base import BaseObject -from ralph.assets.models.choices import ModelVisualizationLayout, ObjectModelType -from ralph.lib.custom_fields.models import CustomFieldMeta, WithCustomFieldsMixin -from ralph.lib.mixins.fields import NullableCharField, NullableCharFieldWithAutoStrip +from ralph.assets.models.choices import ( + ModelVisualizationLayout, + ObjectModelType +) +from ralph.lib.custom_fields.models import ( + CustomFieldMeta, + WithCustomFieldsMixin +) +from ralph.lib.mixins.fields import ( + NullableCharField, + NullableCharFieldWithAutoStrip +) from ralph.lib.mixins.models import ( AdminAbsoluteUrlMixin, NamedMixin, PriceMixin, - TimeStampMixin, + TimeStampMixin ) from ralph.lib.permissions.models import PermByFieldMixin, PermissionsBase diff --git a/src/ralph/assets/models/base.py b/src/ralph/assets/models/base.py index e5e455cda8..ee371cd8bc 100644 --- a/src/ralph/assets/models/base.py +++ b/src/ralph/assets/models/base.py @@ -6,13 +6,16 @@ from django.utils.translation import ugettext_lazy as _ from ralph.attachments.models import AttachmentItem -from ralph.lib.custom_fields.models import CustomFieldMeta, WithCustomFieldsMixin +from ralph.lib.custom_fields.models import ( + CustomFieldMeta, + WithCustomFieldsMixin +) from ralph.lib.mixins.models import TaggableMixin, TimeStampMixin from ralph.lib.permissions.models import PermByFieldMixin, PermissionsBase from ralph.lib.polymorphic.models import ( Polymorphic, PolymorphicBase, - PolymorphicQuerySet, + PolymorphicQuerySet ) from ralph.lib.transitions.models import TransitionWorkflowBase diff --git a/src/ralph/assets/models/components.py b/src/ralph/assets/models/components.py index 196efc76c6..30ba0469be 100644 --- a/src/ralph/assets/models/components.py +++ b/src/ralph/assets/models/components.py @@ -12,10 +12,14 @@ from ralph.assets.models.choices import ( ComponentType, EthernetSpeed, - FibreChannelCardSpeed, + FibreChannelCardSpeed ) from ralph.lib.mixins.fields import MACAddressField, NullableCharField -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + TimeStampMixin +) MAC_RE = re.compile(r"^\s*([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\s*$") MAC_ERROR_MSG = "'%(value)s' is not a valid MAC address." diff --git a/src/ralph/assets/models/configuration.py b/src/ralph/assets/models/configuration.py index dd40299789..0b0672787d 100644 --- a/src/ralph/assets/models/configuration.py +++ b/src/ralph/assets/models/configuration.py @@ -6,7 +6,10 @@ from mptt.models import MPTTModel, MPTTModelBase, TreeForeignKey from ralph.assets.models.base import BaseObject -from ralph.lib.custom_fields.models import CustomFieldMeta, WithCustomFieldsMixin +from ralph.lib.custom_fields.models import ( + CustomFieldMeta, + WithCustomFieldsMixin +) from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin dir_file_name_validator = RegexValidator(regex=r"\w+") diff --git a/src/ralph/assets/signals.py b/src/ralph/assets/signals.py index 53ec262640..8d55c0d62b 100644 --- a/src/ralph/assets/signals.py +++ b/src/ralph/assets/signals.py @@ -7,7 +7,7 @@ from ralph.assets.models import BaseObject from ralph.data_center.publishers import ( publish_host_update, - publish_host_update_from_related_model, + publish_host_update_from_related_model ) from ralph.lib.custom_fields.signals import api_post_create, api_post_update from ralph.signals import post_commit diff --git a/src/ralph/assets/subscribers.py b/src/ralph/assets/subscribers.py index c175a79f35..a3cb2fc95a 100644 --- a/src/ralph/assets/subscribers.py +++ b/src/ralph/assets/subscribers.py @@ -10,7 +10,7 @@ Environment, ProfitCenter, Service, - ServiceEnvironment, + ServiceEnvironment ) from ralph.assets.models.base import BaseObject diff --git a/src/ralph/assets/tests/factories.py b/src/ralph/assets/tests/factories.py index 4aea1dbe8c..45c08bea65 100644 --- a/src/ralph/assets/tests/factories.py +++ b/src/ralph/assets/tests/factories.py @@ -14,7 +14,7 @@ ManufacturerKind, ProfitCenter, Service, - ServiceEnvironment, + ServiceEnvironment ) from ralph.assets.models.base import BaseObject from ralph.assets.models.choices import ComponentType, ObjectModelType @@ -24,9 +24,12 @@ Ethernet, FibreChannelCard, Memory, - Processor, + Processor +) +from ralph.assets.models.configuration import ( + ConfigurationClass, + ConfigurationModule ) -from ralph.assets.models.configuration import ConfigurationClass, ConfigurationModule def next_mac(n): diff --git a/src/ralph/assets/tests/test_api.py b/src/ralph/assets/tests/test_api.py index 60bb50bfd7..f7e1d1c6dd 100644 --- a/src/ralph/assets/tests/test_api.py +++ b/src/ralph/assets/tests/test_api.py @@ -17,7 +17,7 @@ Manufacturer, ObjectModelType, Service, - ServiceEnvironment, + ServiceEnvironment ) from ralph.assets.tests.factories import ( BusinessSegmentFactory, @@ -30,19 +30,19 @@ ManufacturerFactory, ProfitCenterFactory, ServiceEnvironmentFactory, - ServiceFactory, + ServiceFactory ) from ralph.back_office.models import BackOfficeAsset from ralph.back_office.tests.factories import BackOfficeAssetFactory from ralph.configuration_management.models import SCMCheckResult from ralph.configuration_management.tests.factories import SCMStatusCheckFactory -from ralph.data_center.models import VIP, Cluster, Database, DataCenterAsset +from ralph.data_center.models import Cluster, Database, DataCenterAsset, VIP from ralph.data_center.tests.factories import ( ClusterFactory, DatabaseFactory, DataCenterAssetFactory, DataCenterAssetFullFactory, - VIPFactory, + VIPFactory ) from ralph.domains.models import Domain from ralph.domains.tests.factories import DomainFactory @@ -60,16 +60,21 @@ DesignFactory, PatentFactory, TradeMarkFactory, - UtilityModelFactory, + UtilityModelFactory +) +from ralph.virtual.models import ( + CloudFlavor, + CloudHost, + CloudProject, + VirtualServer ) -from ralph.virtual.models import CloudFlavor, CloudHost, CloudProject, VirtualServer from ralph.virtual.tests.factories import ( CloudFlavorFactory, CloudHostFactory, CloudHostFullFactory, CloudProjectFactory, VirtualServerFactory, - VirtualServerFullFactory, + VirtualServerFullFactory ) diff --git a/src/ralph/assets/tests/test_models.py b/src/ralph/assets/tests/test_models.py index 9cc1835a88..7472b92fe8 100644 --- a/src/ralph/assets/tests/test_models.py +++ b/src/ralph/assets/tests/test_models.py @@ -4,7 +4,7 @@ from ralph.assets.tests.factories import ( ConfigurationClassFactory, ConfigurationModuleFactory, - EthernetFactory, + EthernetFactory ) from ralph.networks.tests.factories import IPAddressFactory from ralph.tests import RalphTestCase diff --git a/src/ralph/assets/tests/test_signals.py b/src/ralph/assets/tests/test_signals.py index 144be90dc5..0b25369768 100644 --- a/src/ralph/assets/tests/test_signals.py +++ b/src/ralph/assets/tests/test_signals.py @@ -9,12 +9,12 @@ from ralph.data_center.tests.factories import ( ClusterFactory, ConfigurationClassFactory, - DataCenterAssetFactory, + DataCenterAssetFactory ) from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue, + CustomFieldValue ) from ralph.networks.models import IPAddress from ralph.tests import RalphTestCase diff --git a/src/ralph/assets/tests/test_subscribers.py b/src/ralph/assets/tests/test_subscribers.py index 548ac91d47..fe8d3d7349 100644 --- a/src/ralph/assets/tests/test_subscribers.py +++ b/src/ralph/assets/tests/test_subscribers.py @@ -9,7 +9,10 @@ from ralph.accounts.tests.factories import UserFactory from ralph.assets.models import Service from ralph.assets.subscribers import ACTION_TYPE -from ralph.assets.tests.factories import ServiceEnvironmentFactory, ServiceFactory +from ralph.assets.tests.factories import ( + ServiceEnvironmentFactory, + ServiceFactory +) from ralph.data_center.tests.factories import DataCenterAssetFactory diff --git a/src/ralph/assets/views.py b/src/ralph/assets/views.py index 336a1d8f01..a48c18e0c6 100644 --- a/src/ralph/assets/views.py +++ b/src/ralph/assets/views.py @@ -7,7 +7,7 @@ Ethernet, FibreChannelCard, Memory, - Processor, + Processor ) from ralph.networks.forms import EthernetLockDeleteForm, NetworkInlineFormset diff --git a/src/ralph/back_office/admin.py b/src/ralph/back_office/admin.py index 25e7e9f747..dd5ae1a214 100644 --- a/src/ralph/back_office/admin.py +++ b/src/ralph/back_office/admin.py @@ -7,7 +7,11 @@ from ralph.admin.decorators import register from ralph.admin.filters import LiquidatedStatusFilter, TagsListFilter -from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphTabularInline +from ralph.admin.mixins import ( + BulkEditChangeListMixin, + RalphAdmin, + RalphTabularInline +) from ralph.admin.sites import ralph_site from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.admin.views.multiadd import MulitiAddAdminMixin @@ -16,7 +20,11 @@ from ralph.assets.invoice_report import AssetInvoiceReportMixin from ralph.assets.models import ObjectModelType from ralph.attachments.admin import AttachmentsMixin -from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse +from ralph.back_office.models import ( + BackOfficeAsset, + OfficeInfrastructure, + Warehouse +) from ralph.data_importer import resources from ralph.lib.custom_fields.admin import CustomFieldValueAdminMixin from ralph.lib.mixins.forms import AssetFormMixin, PriceFormMixin diff --git a/src/ralph/back_office/api.py b/src/ralph/back_office/api.py index ef75a51cea..6c8f0b0add 100644 --- a/src/ralph/back_office/api.py +++ b/src/ralph/back_office/api.py @@ -4,7 +4,11 @@ from ralph.assets.api.serializers import AssetSerializer from ralph.assets.api.views import base_object_descendant_prefetch_related from ralph.back_office.admin import BackOfficeAssetAdmin -from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse +from ralph.back_office.models import ( + BackOfficeAsset, + OfficeInfrastructure, + Warehouse +) class WarehouseSerializer(RalphAPISerializer): diff --git a/src/ralph/back_office/models.py b/src/ralph/back_office/models.py index 2b2faee417..73e748378d 100644 --- a/src/ralph/back_office/models.py +++ b/src/ralph/back_office/models.py @@ -20,13 +20,17 @@ Asset, AssetLastHostname, AssetModel, - ServiceEnvironment, + ServiceEnvironment ) from ralph.assets.utils import move_parents_models from ralph.attachments.utils import send_transition_attachments_to_user from ralph.lib.hooks import get_hook from ralph.lib.mixins.fields import NullableCharField -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + TimeStampMixin +) from ralph.lib.transitions.conf import get_report_name_for_transition_id from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.fields import TransitionField diff --git a/src/ralph/back_office/tests/factories.py b/src/ralph/back_office/tests/factories.py index a98e99c4be..1dbe30297a 100644 --- a/src/ralph/back_office/tests/factories.py +++ b/src/ralph/back_office/tests/factories.py @@ -9,9 +9,13 @@ from ralph.assets.tests.factories import ( AssetHolderFactory, BackOfficeAssetModelFactory, - BudgetInfoFactory, + BudgetInfoFactory +) +from ralph.back_office.models import ( + BackOfficeAsset, + OfficeInfrastructure, + Warehouse ) -from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse from ralph.security.tests.factories import SecurityScanFactory date_now = datetime.now().date() diff --git a/src/ralph/back_office/tests/test_api.py b/src/ralph/back_office/tests/test_api.py index d67b5942d0..2c546586b5 100644 --- a/src/ralph/back_office/tests/test_api.py +++ b/src/ralph/back_office/tests/test_api.py @@ -7,10 +7,13 @@ from ralph.assets.tests.factories import ( AssetHolderFactory, BackOfficeAssetModelFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory ) from ralph.back_office.models import BackOfficeAsset -from ralph.back_office.tests.factories import BackOfficeAssetFactory, WarehouseFactory +from ralph.back_office.tests.factories import ( + BackOfficeAssetFactory, + WarehouseFactory +) class BackOfficeAssetAPITests(RalphAPITestCase): diff --git a/src/ralph/back_office/tests/test_models.py b/src/ralph/back_office/tests/test_models.py index c8e67b0aa6..ee2c97dc44 100644 --- a/src/ralph/back_office/tests/test_models.py +++ b/src/ralph/back_office/tests/test_models.py @@ -8,7 +8,7 @@ from django.contrib.messages.storage.fallback import FallbackStorage from django.core import mail from django.core.files.uploadedfile import SimpleUploadedFile -from django.test import RequestFactory, SimpleTestCase, override_settings +from django.test import override_settings, RequestFactory, SimpleTestCase from django.urls import reverse from django.utils import timezone @@ -20,25 +20,25 @@ BackOfficeAssetModelFactory, CategoryFactory, DataCenterAssetModelFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory ) from ralph.attachments.models import Attachment from ralph.back_office.helpers import EmailContext from ralph.back_office.models import ( - BackOfficeAsset, - BackOfficeAssetStatus, _check_assets_owner, + BackOfficeAsset, + BackOfficeAssetStatus ) from ralph.back_office.tests.factories import BackOfficeAssetFactory from ralph.data_center.models import DataCenterAsset, DataCenterAssetStatus from ralph.data_center.tests.factories import RackFactory from ralph.lib.external_services import ExternalService from ralph.lib.transitions.models import ( - Transition, - TransitionModel, - TransitionNotAllowedError, _check_instances_for_transition, run_field_transition, + Transition, + TransitionModel, + TransitionNotAllowedError ) from ralph.lib.transitions.tests import TransitionTestCase from ralph.licences.tests.factories import LicenceFactory diff --git a/src/ralph/configuration_management/views.py b/src/ralph/configuration_management/views.py index 9b76353b9f..59f886e902 100644 --- a/src/ralph/configuration_management/views.py +++ b/src/ralph/configuration_management/views.py @@ -10,7 +10,6 @@ from ralph.admin.helpers import get_admin_url from ralph.admin.views.extra import RalphDetailView from ralph.configuration_management.models import SCMCheckResult - # NOTE(romcheg): These functions could be moved to a common place from ralph.security.views import _linkify, _url_name_for_change_view diff --git a/src/ralph/dashboards/api/views.py b/src/ralph/dashboards/api/views.py index 8366026377..ce1e4a078d 100644 --- a/src/ralph/dashboards/api/views.py +++ b/src/ralph/dashboards/api/views.py @@ -1,6 +1,9 @@ from rest_framework.viewsets import ReadOnlyModelViewSet -from ralph.dashboards.api.serializers import GraphSerializer, GraphSerializerDetail +from ralph.dashboards.api.serializers import ( + GraphSerializer, + GraphSerializerDetail +) from ralph.dashboards.models import Graph diff --git a/src/ralph/dashboards/models.py b/src/ralph/dashboards/models.py index 46c2a7cc20..2bd1a925c9 100644 --- a/src/ralph/dashboards/models.py +++ b/src/ralph/dashboards/models.py @@ -9,7 +9,11 @@ from ralph.dashboards.filter_parser import FilterParser from ralph.dashboards.renderers import HorizontalBar, PieChart, VerticalBar -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + TimeStampMixin +) def _unpack_series(series): diff --git a/src/ralph/dashboards/tests/test_parser.py b/src/ralph/dashboards/tests/test_parser.py index 6fa9328322..b2b02b8f9b 100644 --- a/src/ralph/dashboards/tests/test_parser.py +++ b/src/ralph/dashboards/tests/test_parser.py @@ -19,10 +19,13 @@ from ralph.data_center.models import DataCenterAsset from ralph.data_center.tests.factories import ( DataCenterAssetFactory, - DataCenterAssetFullFactory, + DataCenterAssetFullFactory ) from ralph.security.models import Vulnerability -from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory +from ralph.security.tests.factories import ( + SecurityScanFactory, + VulnerabilityFactory +) from ralph.tests.models import Bar ARGS, KWARGS = (0, 1) diff --git a/src/ralph/data_center/admin.py b/src/ralph/data_center/admin.py index 3090df6b14..dc56a0cfad 100644 --- a/src/ralph/data_center/admin.py +++ b/src/ralph/data_center/admin.py @@ -4,7 +4,7 @@ from django.conf import settings from django.contrib.admin import SimpleListFilter -from django.contrib.admin.views.main import ORDER_VAR, ChangeList +from django.contrib.admin.views.main import ChangeList, ORDER_VAR from django.contrib.contenttypes.models import ContentType from django.db.models import Prefetch, Q from django.urls import reverse @@ -22,14 +22,14 @@ RelatedAutocompleteFieldListFilter, TagsListFilter, TreeRelatedAutocompleteFilterWithDescendants, - VulnerabilitesByPatchDeadline, + VulnerabilitesByPatchDeadline ) from ralph.admin.helpers import generate_html_link from ralph.admin.mixins import ( BulkEditChangeListMixin, RalphAdmin, RalphAdminImportExportMixin, - RalphTabularInline, + RalphTabularInline ) from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.admin.views.main import RalphChangeList @@ -41,7 +41,7 @@ from ralph.attachments.admin import AttachmentsMixin from ralph.configuration_management.views import ( SCMCheckInfo, - SCMStatusCheckInChangeListMixin, + SCMStatusCheckInChangeListMixin ) from ralph.data_center.forms import DataCenterAssetForm from ralph.data_center.models.components import DiskShare, DiskShareMount @@ -53,14 +53,14 @@ DataCenterAsset, Rack, RackAccessory, - ServerRoom, + ServerRoom ) from ralph.data_center.models.virtual import ( - VIP, BaseObjectCluster, Cluster, ClusterType, Database, + VIP ) from ralph.data_center.views import RelationsView from ralph.data_importer import resources diff --git a/src/ralph/data_center/api/routers.py b/src/ralph/data_center/api/routers.py index 5abfe8a330..54e98c1e06 100644 --- a/src/ralph/data_center/api/routers.py +++ b/src/ralph/data_center/api/routers.py @@ -11,7 +11,7 @@ RackAccessoryViewSet, RackViewSet, ServerRoomViewSet, - VIPViewSet, + VIPViewSet ) router.register(r"accessories", AccessoryViewSet) diff --git a/src/ralph/data_center/api/serializers.py b/src/ralph/data_center/api/serializers.py index 55335f4bea..3f44db2afb 100644 --- a/src/ralph/data_center/api/serializers.py +++ b/src/ralph/data_center/api/serializers.py @@ -9,11 +9,10 @@ BaseObjectSerializer, ComponentSerializerMixin, NetworkComponentSerializerMixin, - OwnersFromServiceEnvSerializerMixin, + OwnersFromServiceEnvSerializerMixin ) from ralph.configuration_management.api import SCMInfoSerializer from ralph.data_center.models import ( - VIP, Accessory, BaseObjectCluster, Cluster, @@ -24,6 +23,7 @@ Rack, RackAccessory, ServerRoom, + VIP ) from ralph.security.api import SecurityScanSerializer diff --git a/src/ralph/data_center/api/views.py b/src/ralph/data_center/api/views.py index c5c2af8057..7b6dc06cb4 100644 --- a/src/ralph/data_center/api/views.py +++ b/src/ralph/data_center/api/views.py @@ -5,14 +5,14 @@ from ralph.api import RalphAPIViewSet from ralph.assets.api.filters import NetworkableObjectFilters from ralph.assets.api.views import ( - BaseObjectViewSetMixin, base_object_descendant_prefetch_related, + BaseObjectViewSetMixin ) from ralph.assets.models import ( ConfigurationClass, ConfigurationModule, Ethernet, - ServiceEnvironment, + ServiceEnvironment ) from ralph.data_center.admin import DataCenterAssetAdmin from ralph.data_center.api.serializers import ( @@ -27,10 +27,9 @@ RackAccessorySerializer, RackSerializer, ServerRoomSerializer, - VIPSerializer, + VIPSerializer ) from ralph.data_center.models import ( - VIP, Accessory, BaseObjectCluster, Cluster, @@ -41,6 +40,7 @@ Rack, RackAccessory, ServerRoom, + VIP ) from ralph.virtual.models import CloudHost, VirtualServer diff --git a/src/ralph/data_center/models/physical.py b/src/ralph/data_center/models/physical.py index f9d9a37a6e..92ed638c5b 100644 --- a/src/ralph/data_center/models/physical.py +++ b/src/ralph/data_center/models/physical.py @@ -1,14 +1,18 @@ # -*- coding: utf-8 -*- import logging import re -from collections import OrderedDict, namedtuple +from collections import namedtuple, OrderedDict from itertools import chain from dj.choices import Choices, Country from django import forms from django.conf import settings from django.core.exceptions import ValidationError -from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator +from django.core.validators import ( + MaxValueValidator, + MinValueValidator, + RegexValidator +) from django.db import models, transaction from django.db.models import Q from django.urls import reverse @@ -31,7 +35,7 @@ ConnectionType, DataCenterAssetStatus, Orientation, - RackOrientation, + RackOrientation ) from ralph.data_center.models.mixins import WithManagementIPMixin from ralph.data_center.publishers import publish_host_update diff --git a/src/ralph/data_center/models/virtual.py b/src/ralph/data_center/models/virtual.py index 8fa9befffe..898999f5c2 100644 --- a/src/ralph/data_center/models/virtual.py +++ b/src/ralph/data_center/models/virtual.py @@ -8,12 +8,15 @@ from ralph.assets.models.base import BaseObject from ralph.assets.utils import DNSaaSPublisherMixin from ralph.data_center.models.mixins import WithManagementIPMixin -from ralph.data_center.models.physical import DataCenterAsset, NetworkableBaseObject +from ralph.data_center.models.physical import ( + DataCenterAsset, + NetworkableBaseObject +) from ralph.lib.mixins.fields import BaseObjectForeignKey, NullableCharField from ralph.lib.mixins.models import ( AdminAbsoluteUrlMixin, NamedMixin, - PreviousStateMixin, + PreviousStateMixin ) from ralph.lib.transitions.fields import TransitionField from ralph.networks.models.networks import IPAddress diff --git a/src/ralph/data_center/subscribers.py b/src/ralph/data_center/subscribers.py index f2e4d82014..99bb760241 100644 --- a/src/ralph/data_center/subscribers.py +++ b/src/ralph/data_center/subscribers.py @@ -7,7 +7,7 @@ from django.db import transaction from ralph.assets.models.assets import ServiceEnvironment -from ralph.data_center.models import VIP, Cluster, ClusterType, VIPProtocol +from ralph.data_center.models import Cluster, ClusterType, VIP, VIPProtocol from ralph.networks.models.networks import Ethernet, IPAddress logger = logging.getLogger(__name__) diff --git a/src/ralph/data_center/tests/factories.py b/src/ralph/data_center/tests/factories.py index 4229eef09e..3663f86882 100644 --- a/src/ralph/data_center/tests/factories.py +++ b/src/ralph/data_center/tests/factories.py @@ -17,27 +17,27 @@ FibreChannelCardFactory, MemoryFactory, ProcessorFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory ) from ralph.data_center.models import BaseObjectCluster from ralph.data_center.models.choices import ConnectionType from ralph.data_center.models.components import DiskShare, DiskShareMount from ralph.data_center.models.physical import ( - ACCESSORY_DATA, Accessory, + ACCESSORY_DATA, Connection, DataCenter, DataCenterAsset, Rack, RackAccessory, - ServerRoom, + ServerRoom ) from ralph.data_center.models.virtual import ( - VIP, Cluster, ClusterType, Database, - VIPProtocol, + VIP, + VIPProtocol ) from ralph.security.tests.factories import SecurityScanFactory diff --git a/src/ralph/data_center/tests/test_admin.py b/src/ralph/data_center/tests/test_admin.py index 79127af3c0..beb7eae472 100644 --- a/src/ralph/data_center/tests/test_admin.py +++ b/src/ralph/data_center/tests/test_admin.py @@ -3,16 +3,22 @@ from django.contrib.auth import get_user_model from django.core import mail from django.db import connection, transaction -from django.test import RequestFactory, TransactionTestCase, override_settings +from django.test import override_settings, RequestFactory, TransactionTestCase from ralph.accounts.tests.factories import UserFactory -from ralph.assets.tests.factories import ServiceEnvironmentFactory, ServiceFactory +from ralph.assets.tests.factories import ( + ServiceEnvironmentFactory, + ServiceFactory +) from ralph.data_center.models import DataCenterAsset -from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory +from ralph.data_center.tests.factories import ( + DataCenterAssetFactory, + RackFactory +) from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue, + CustomFieldValue ) diff --git a/src/ralph/data_center/tests/test_api.py b/src/ralph/data_center/tests/test_api.py index 569f7d706d..44d9dfb92e 100644 --- a/src/ralph/data_center/tests/test_api.py +++ b/src/ralph/data_center/tests/test_api.py @@ -7,7 +7,7 @@ AssetHolderFactory, DataCenterAssetModelFactory, EthernetFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory ) from ralph.data_center.models import ( BaseObjectCluster, @@ -16,7 +16,7 @@ Orientation, Rack, RackAccessory, - RackOrientation, + RackOrientation ) from ralph.data_center.tests.factories import ( AccessoryFactory, @@ -26,7 +26,7 @@ DataCenterAssetFullFactory, RackAccessoryFactory, RackFactory, - ServerRoomFactory, + ServerRoomFactory ) from ralph.networks.tests.factories import IPAddressFactory from ralph.virtual.tests.factories import CloudHostFactory, VirtualServerFactory diff --git a/src/ralph/data_center/tests/test_forms.py b/src/ralph/data_center/tests/test_forms.py index 9e63e80bcf..f16e2cd0d3 100755 --- a/src/ralph/data_center/tests/test_forms.py +++ b/src/ralph/data_center/tests/test_forms.py @@ -7,7 +7,10 @@ from ralph.assets.models import Ethernet, ObjectModelType from ralph.assets.tests.factories import DataCenterAssetModelFactory from ralph.data_center.models import DataCenterAsset -from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory +from ralph.data_center.tests.factories import ( + DataCenterAssetFactory, + RackFactory +) from ralph.networks.forms import validate_is_management from ralph.networks.models import IPAddress from ralph.networks.tests.factories import IPAddressFactory diff --git a/src/ralph/data_center/tests/test_models.py b/src/ralph/data_center/tests/test_models.py index 4f1f9005f5..cc2b7f7d43 100644 --- a/src/ralph/data_center/tests/test_models.py +++ b/src/ralph/data_center/tests/test_models.py @@ -9,8 +9,8 @@ from ralph.back_office.tests.factories import WarehouseFactory from ralph.data_center.models.choices import DataCenterAssetStatus, Orientation from ralph.data_center.models.physical import ( - DataCenterAsset, assign_additional_hostname_choices, + DataCenterAsset ) from ralph.data_center.models.virtual import BaseObjectCluster from ralph.data_center.tests.factories import ( @@ -18,14 +18,14 @@ ClusterTypeFactory, DataCenterAssetFactory, DataCenterAssetModelFactory, - RackFactory, + RackFactory ) from ralph.lib.transitions.models import Transition, TransitionModel from ralph.networks.models import IPAddress from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory, + NetworkFactory ) from ralph.tests import RalphTestCase diff --git a/src/ralph/data_center/tests/test_signals.py b/src/ralph/data_center/tests/test_signals.py index 2f9a8116b0..a327f8720e 100644 --- a/src/ralph/data_center/tests/test_signals.py +++ b/src/ralph/data_center/tests/test_signals.py @@ -4,7 +4,10 @@ from ralph.data_center.publishers import _get_host_data from ralph.data_center.tests.factories import DataCenterAssetFullFactory -from ralph.virtual.tests.factories import CloudHostFullFactory, VirtualServerFactory +from ralph.virtual.tests.factories import ( + CloudHostFullFactory, + VirtualServerFactory +) class TestPublishing(TestCase): diff --git a/src/ralph/data_center/tests/test_subscribers.py b/src/ralph/data_center/tests/test_subscribers.py index 6d62be1b07..9df633ba5d 100644 --- a/src/ralph/data_center/tests/test_subscribers.py +++ b/src/ralph/data_center/tests/test_subscribers.py @@ -5,17 +5,17 @@ from django.test import TestCase from ralph.assets.tests.factories import ServiceEnvironmentFactory -from ralph.data_center.models import VIP, Cluster, VIPProtocol +from ralph.data_center.models import Cluster, VIP, VIPProtocol from ralph.data_center.subscribers import ( handle_create_vip_event, handle_delete_vip_event, handle_update_vip_event, - validate_vip_event_data, + validate_vip_event_data ) from ralph.data_center.tests.factories import ( ClusterFactory, EthernetFactory, - VIPFactory, + VIPFactory ) from ralph.networks.models.networks import Ethernet, IPAddress from ralph.networks.tests.factories import IPAddressFactory diff --git a/src/ralph/data_center/tests/test_view.py b/src/ralph/data_center/tests/test_view.py index 2dac52c04c..901c1fe01b 100644 --- a/src/ralph/data_center/tests/test_view.py +++ b/src/ralph/data_center/tests/test_view.py @@ -9,18 +9,21 @@ from ralph.data_center.tests.factories import ( ClusterFactory, DataCenterAssetFactory, - DataCenterAssetFullFactory, + DataCenterAssetFullFactory ) from ralph.data_center.views import RelationsView from ralph.security.models import ScanStatus -from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory +from ralph.security.tests.factories import ( + SecurityScanFactory, + VulnerabilityFactory +) from ralph.tests.mixins import ClientMixin from ralph.virtual.models import CloudHost, VirtualServer from ralph.virtual.tests.factories import ( CloudHostFactory, CloudHostFullFactory, VirtualServerFactory, - VirtualServerFullFactory, + VirtualServerFullFactory ) diff --git a/src/ralph/data_importer/management/commands/create_preboot_configuration.py b/src/ralph/data_importer/management/commands/create_preboot_configuration.py index d2110977cd..8111cf7695 100644 --- a/src/ralph/data_importer/management/commands/create_preboot_configuration.py +++ b/src/ralph/data_importer/management/commands/create_preboot_configuration.py @@ -1,7 +1,11 @@ from django.core.management import BaseCommand from django.db import transaction -from ralph.deployment.models import Preboot, PrebootConfiguration, PrebootItemType +from ralph.deployment.models import ( + Preboot, + PrebootConfiguration, + PrebootItemType +) class Command(BaseCommand): diff --git a/src/ralph/data_importer/management/commands/create_server_model.py b/src/ralph/data_importer/management/commands/create_server_model.py index 6d14020862..dd9e4142f1 100644 --- a/src/ralph/data_importer/management/commands/create_server_model.py +++ b/src/ralph/data_importer/management/commands/create_server_model.py @@ -1,6 +1,11 @@ from django.core.management import BaseCommand -from ralph.assets.models import AssetModel, Category, Manufacturer, ObjectModelType +from ralph.assets.models import ( + AssetModel, + Category, + Manufacturer, + ObjectModelType +) DEFAULT_MODEL_CATEGORY = "generic server category" DEFAULT_MODEL_NAME = "Model A" diff --git a/src/ralph/data_importer/management/commands/demodata.py b/src/ralph/data_importer/management/commands/demodata.py index cff3dd4484..49f88a810b 100644 --- a/src/ralph/data_importer/management/commands/demodata.py +++ b/src/ralph/data_importer/management/commands/demodata.py @@ -11,7 +11,11 @@ from django.core.management.base import BaseCommand from ralph.accounts.models import RalphUser -from ralph.accounts.tests.factories import GroupFactory, RegionFactory, UserFactory +from ralph.accounts.tests.factories import ( + GroupFactory, + RegionFactory, + UserFactory +) from ralph.assets.tests.factories import ( BackOfficeAssetModelFactory, BusinessSegmentFactory, @@ -19,7 +23,7 @@ DataCenterAssetModelFactory, DataCenterCategoryFactory, ProfitCenterFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory ) from ralph.back_office.models import BackOfficeAsset, BackOfficeAssetStatus from ralph.back_office.tests.factories import BackOfficeAssetFactory @@ -30,16 +34,15 @@ DataCenterAssetFactory, RackAccessoryFactory, RackFactory, - ServerRoomFactory, -) -from ralph.data_importer.management.commands.create_transitions import ( - Command as TransitionCommand, + ServerRoomFactory ) +from ralph.data_importer.management.commands.create_transitions import \ + Command as TransitionCommand from ralph.licences.models import LicenceUser from ralph.licences.tests.factories import ( BaseObjectLicenceFactory, DataCenterAssetLicenceFactory, - LicenceFactory, + LicenceFactory ) from ralph.reports.models import Report, ReportLanguage, ReportTemplate from ralph.supports.tests.factories import BaseObjectsSupportFactory diff --git a/src/ralph/data_importer/management/commands/import_attachments.py b/src/ralph/data_importer/management/commands/import_attachments.py index 8ec0385f4b..49d88ec708 100644 --- a/src/ralph/data_importer/management/commands/import_attachments.py +++ b/src/ralph/data_importer/management/commands/import_attachments.py @@ -16,7 +16,10 @@ from ralph.attachments.models import Attachment, AttachmentItem from ralph.back_office.models import BackOfficeAsset from ralph.data_center.models.physical import DataCenterAsset -from ralph.data_importer.models import ImportedObjectDoesNotExist, ImportedObjects +from ralph.data_importer.models import ( + ImportedObjectDoesNotExist, + ImportedObjects +) from ralph.lib.transitions.models import TransitionsHistory from ralph.licences.models import Licence from ralph.supports.models import Support diff --git a/src/ralph/data_importer/management/commands/initial_data.py b/src/ralph/data_importer/management/commands/initial_data.py index 3c8353d2b0..c66ca47bbb 100644 --- a/src/ralph/data_importer/management/commands/initial_data.py +++ b/src/ralph/data_importer/management/commands/initial_data.py @@ -1,20 +1,17 @@ import ipaddress from django.contrib.auth import get_user_model -from django.core.management import BaseCommand, CommandError, call_command +from django.core.management import BaseCommand, call_command, CommandError from django.db import transaction from ralph.accounts.tests.factories import RegionFactory from ralph.assets.models import ConfigurationClass, ConfigurationModule -from ralph.data_importer.management.commands.create_network import ( - Command as NetworkCommand, -) -from ralph.data_importer.management.commands.create_server_model import ( - Command as ServerModelCommand, -) -from ralph.data_importer.management.commands.create_transitions import ( - Command as TransitionsCommand, -) +from ralph.data_importer.management.commands.create_network import \ + Command as NetworkCommand +from ralph.data_importer.management.commands.create_server_model import \ + Command as ServerModelCommand +from ralph.data_importer.management.commands.create_transitions import \ + Command as TransitionsCommand class Command(BaseCommand): diff --git a/src/ralph/data_importer/mixins.py b/src/ralph/data_importer/mixins.py index a49f5fdd3f..773672f24d 100644 --- a/src/ralph/data_importer/mixins.py +++ b/src/ralph/data_importer/mixins.py @@ -10,7 +10,7 @@ ExportForeignKeyStrWidget, ExportManyToManyStrTroughWidget, ExportManyToManyStrWidget, - ManyToManyThroughWidget, + ManyToManyThroughWidget ) diff --git a/src/ralph/data_importer/resources.py b/src/ralph/data_importer/resources.py index c776ec2d3f..f1f1bcd50c 100644 --- a/src/ralph/data_importer/resources.py +++ b/src/ralph/data_importer/resources.py @@ -6,11 +6,18 @@ from import_export import fields, resources, widgets from ralph.accounts.models import Region -from ralph.assets.models import BaseObject, assets, base, configuration -from ralph.back_office.models import BackOfficeAsset, OfficeInfrastructure, Warehouse +from ralph.assets.models import assets, base, BaseObject, configuration +from ralph.back_office.models import ( + BackOfficeAsset, + OfficeInfrastructure, + Warehouse +) from ralph.data_center.models import hosts, physical from ralph.data_importer.fields import PriceField, ThroughField -from ralph.data_importer.mixins import ImportForeignKeyMeta, ImportForeignKeyMixin +from ralph.data_importer.mixins import ( + ImportForeignKeyMeta, + ImportForeignKeyMixin +) from ralph.data_importer.widgets import ( AssetServiceEnvWidget, AssetServiceUidWidget, @@ -23,7 +30,7 @@ PriceAmountWidget, PriceCurrencyWidget, UserManyToManyWidget, - UserWidget, + UserWidget ) from ralph.domains.models.domains import Domain, DomainContract from ralph.licences.models import ( @@ -31,7 +38,7 @@ Licence, LicenceType, LicenceUser, - Software, + Software ) from ralph.networks.models import networks from ralph.operations.models import Operation, OperationType diff --git a/src/ralph/data_importer/tests/test_commands.py b/src/ralph/data_importer/tests/test_commands.py index 4485a84e67..fb62c6cb7c 100644 --- a/src/ralph/data_importer/tests/test_commands.py +++ b/src/ralph/data_importer/tests/test_commands.py @@ -15,7 +15,7 @@ Environment, Manufacturer, Service, - ServiceEnvironment, + ServiceEnvironment ) from ralph.assets.models.choices import ObjectModelType from ralph.back_office.models import BackOfficeAsset, Warehouse @@ -26,11 +26,15 @@ from ralph.data_importer.management.commands.create_server_model import ( DEFAULT_MODEL_CATEGORY, DEFAULT_MODEL_MANUFACTURER, - DEFAULT_MODEL_NAME, + DEFAULT_MODEL_NAME ) from ralph.data_importer.models import ImportedObjects from ralph.data_importer.resources import AssetModelResource -from ralph.deployment.models import Preboot, PrebootConfiguration, PrebootItemType +from ralph.deployment.models import ( + Preboot, + PrebootConfiguration, + PrebootItemType +) from ralph.dhcp.models import DNSServerGroup from ralph.lib.transitions.conf import DEFAULT_ASYNC_TRANSITION_SERVICE_NAME from ralph.lib.transitions.models import Transition, TransitionModel diff --git a/src/ralph/data_importer/tests/test_export.py b/src/ralph/data_importer/tests/test_export.py index e9ee478985..bec38da8a5 100644 --- a/src/ralph/data_importer/tests/test_export.py +++ b/src/ralph/data_importer/tests/test_export.py @@ -15,14 +15,14 @@ BackOfficeAssetLicenceFactory, DataCenterAssetLicenceFactory, LicenceFactory, - LicenceUserFactory, + LicenceUserFactory ) from ralph.supports.models import BaseObjectsSupport, Support from ralph.supports.tests.factories import ( BackOfficeAssetSupportFactory, BaseObjectsSupportFactory, DataCenterAssetSupportFactory, - SupportFactory, + SupportFactory ) diff --git a/src/ralph/data_importer/tests/test_fields.py b/src/ralph/data_importer/tests/test_fields.py index f8e0da629d..61cae9e886 100644 --- a/src/ralph/data_importer/tests/test_fields.py +++ b/src/ralph/data_importer/tests/test_fields.py @@ -5,7 +5,10 @@ from ralph.assets.models import BaseObject from ralph.back_office.tests.factories import BackOfficeAssetFactory from ralph.data_importer.fields import ThroughField -from ralph.data_importer.widgets import ManyToManyThroughWidget, UserManyToManyWidget +from ralph.data_importer.widgets import ( + ManyToManyThroughWidget, + UserManyToManyWidget +) from ralph.licences.models import BaseObjectLicence, LicenceUser from ralph.licences.tests.factories import LicenceFactory diff --git a/src/ralph/data_importer/tests/test_widgets.py b/src/ralph/data_importer/tests/test_widgets.py index 59de85aa99..9e28ec9173 100644 --- a/src/ralph/data_importer/tests/test_widgets.py +++ b/src/ralph/data_importer/tests/test_widgets.py @@ -3,10 +3,13 @@ from ralph.assets.models import BaseObject from ralph.data_importer.widgets import ( ExportManyToManyStrTroughWidget, - ManyToManyThroughWidget, + ManyToManyThroughWidget ) from ralph.licences.models import BaseObjectLicence -from ralph.licences.tests.factories import DataCenterAssetLicenceFactory, LicenceFactory +from ralph.licences.tests.factories import ( + DataCenterAssetLicenceFactory, + LicenceFactory +) class ManyToManyThroughWidgetTestCase(TestCase): diff --git a/src/ralph/dc_view/serializers/models_serializer.py b/src/ralph/dc_view/serializers/models_serializer.py index f6ca7395b8..4caa64b0fd 100644 --- a/src/ralph/dc_view/serializers/models_serializer.py +++ b/src/ralph/dc_view/serializers/models_serializer.py @@ -8,7 +8,7 @@ DataCenterAsset, Rack, RackAccessory, - ServerRoom, + ServerRoom ) TYPE_EMPTY = "empty" diff --git a/src/ralph/dc_view/tests.py b/src/ralph/dc_view/tests.py index aae6ee43c7..8b32105faf 100644 --- a/src/ralph/dc_view/tests.py +++ b/src/ralph/dc_view/tests.py @@ -9,7 +9,7 @@ DataCenterAssetModelFactory, EnvironmentFactory, ServiceEnvironment, - ServiceFactory, + ServiceFactory ) from ralph.data_center.models.choices import Orientation from ralph.data_center.tests.factories import ( @@ -17,9 +17,12 @@ DataCenterAssetFactory, RackAccessoryFactory, RackFactory, - ServerRoomFactory, + ServerRoomFactory +) +from ralph.dc_view.serializers.models_serializer import ( + TYPE_ACCESSORY, + TYPE_ASSET ) -from ralph.dc_view.serializers.models_serializer import TYPE_ACCESSORY, TYPE_ASSET class TestRestAssetInfoPerRack(TestCase): diff --git a/src/ralph/dc_view/views/api.py b/src/ralph/dc_view/views/api.py index c5b214728d..4e31081689 100644 --- a/src/ralph/dc_view/views/api.py +++ b/src/ralph/dc_view/views/api.py @@ -9,7 +9,7 @@ RackAccessorySerializer, RackBaseSerializer, RackSerializer, - SRSerializer, + SRSerializer ) diff --git a/src/ralph/deployment/admin.py b/src/ralph/deployment/admin.py index b79d7a30a3..7ce7daa54d 100644 --- a/src/ralph/deployment/admin.py +++ b/src/ralph/deployment/admin.py @@ -8,7 +8,7 @@ Preboot, PrebootConfiguration, PrebootFile, - PrebootItem, + PrebootItem ) diff --git a/src/ralph/deployment/deployment.py b/src/ralph/deployment/deployment.py index 653b3f2cbc..f4c2435e6d 100644 --- a/src/ralph/deployment/deployment.py +++ b/src/ralph/deployment/deployment.py @@ -39,7 +39,7 @@ from ralph.dns.dnsaas import DNSaaS from ralph.dns.forms import RecordType from ralph.dns.views import DNSaaSIntegrationNotEnabledError -from ralph.lib.mixins.forms import OTHER, ChoiceFieldWithOtherOption +from ralph.lib.mixins.forms import ChoiceFieldWithOtherOption, OTHER from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.exceptions import FreezeAsyncTransition from ralph.networks.models import IPAddress, Network, NetworkEnvironment diff --git a/src/ralph/deployment/mixins.py b/src/ralph/deployment/mixins.py index 695e6b6f00..6e2f140f18 100644 --- a/src/ralph/deployment/mixins.py +++ b/src/ralph/deployment/mixins.py @@ -1,7 +1,10 @@ from django.contrib import messages from django.utils.safestring import mark_safe -from ralph.lib.transitions.models import TransitionJob, TransitionJobActionStatus +from ralph.lib.transitions.models import ( + TransitionJob, + TransitionJobActionStatus +) def get_actions_statuses_as_html(transition): diff --git a/src/ralph/deployment/tests/test_deployment.py b/src/ralph/deployment/tests/test_deployment.py index 9de8ffa8e6..ccc45a4302 100644 --- a/src/ralph/deployment/tests/test_deployment.py +++ b/src/ralph/deployment/tests/test_deployment.py @@ -3,15 +3,18 @@ from ddt import data, ddt, unpack from django.core.exceptions import ValidationError -from django.test import TestCase, override_settings +from django.test import override_settings, TestCase from ralph.assets.models import Ethernet from ralph.assets.tests.factories import ServiceEnvironmentFactory -from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory +from ralph.data_center.tests.factories import ( + DataCenterAssetFactory, + RackFactory +) from ralph.deployment.deployment import ( autocomplete_service_env, check_if_network_environment_exists, - validate_ip_address, + validate_ip_address ) from ralph.deployment.tests.factories import _get_deployment from ralph.deployment.utils import _render_configuration @@ -20,7 +23,7 @@ from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory, + NetworkFactory ) from ralph.virtual.tests.factories import VirtualServerFactory diff --git a/src/ralph/deployment/tests/test_transitions.py b/src/ralph/deployment/tests/test_transitions.py index 2a650fbb5b..88ba55f04f 100644 --- a/src/ralph/deployment/tests/test_transitions.py +++ b/src/ralph/deployment/tests/test_transitions.py @@ -7,13 +7,16 @@ from ralph.assets.models import AssetLastHostname from ralph.assets.tests.factories import EthernetFactory from ralph.data_center.models import DataCenterAsset -from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory +from ralph.data_center.tests.factories import ( + DataCenterAssetFactory, + RackFactory +) from ralph.lib.transitions.conf import TRANSITION_ORIGINAL_STATUS from ralph.lib.transitions.tests import TransitionTestCase from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory, + NetworkFactory ) from ralph.virtual.models import VirtualServer from ralph.virtual.tests.factories import VirtualServerFactory diff --git a/src/ralph/deployment/urls.py b/src/ralph/deployment/urls.py index 7aa42cb724..924588bfc8 100644 --- a/src/ralph/deployment/urls.py +++ b/src/ralph/deployment/urls.py @@ -1,6 +1,12 @@ from django.conf.urls import url -from ralph.deployment.views import config, deployment_base, done_ping, files, ipxe +from ralph.deployment.views import ( + config, + deployment_base, + done_ping, + files, + ipxe +) urlpatterns = [ url(r"^boot.ipxe$", ipxe, name="deployment_ipxe"), diff --git a/src/ralph/dhcp/admin.py b/src/ralph/dhcp/admin.py index 0a4b4b916c..15dfd4bbb6 100644 --- a/src/ralph/dhcp/admin.py +++ b/src/ralph/dhcp/admin.py @@ -5,7 +5,12 @@ from ralph.admin.decorators import register from ralph.admin.mixins import RalphAdmin, RalphTabularInline -from ralph.dhcp.models import DHCPServer, DNSServer, DNSServerGroup, DNSServerGroupOrder +from ralph.dhcp.models import ( + DHCPServer, + DNSServer, + DNSServerGroup, + DNSServerGroupOrder +) from ralph.lib.table.table import TableWithUrl diff --git a/src/ralph/dhcp/tests/factories.py b/src/ralph/dhcp/tests/factories.py index afa7fbc283..0e99a4d7f8 100644 --- a/src/ralph/dhcp/tests/factories.py +++ b/src/ralph/dhcp/tests/factories.py @@ -1,7 +1,12 @@ import factory from factory.django import DjangoModelFactory -from ralph.dhcp.models import DHCPServer, DNSServer, DNSServerGroup, DNSServerGroupOrder +from ralph.dhcp.models import ( + DHCPServer, + DNSServer, + DNSServerGroup, + DNSServerGroupOrder +) class DNSServerFactory(DjangoModelFactory): diff --git a/src/ralph/dhcp/tests/test_agent.py b/src/ralph/dhcp/tests/test_agent.py index 3cecfe9e5e..bfc39252ea 100644 --- a/src/ralph/dhcp/tests/test_agent.py +++ b/src/ralph/dhcp/tests/test_agent.py @@ -1,10 +1,10 @@ import logging from ddt import data, ddt, unpack -from dhcp_agent import Cache, DHCPConfigManager from django.contrib.auth import get_user_model from django.test import LiveServerTestCase +from dhcp_agent import Cache, DHCPConfigManager from ralph.data_center.tests.factories import DataCenterFactory from ralph.dhcp.models import DHCPServer diff --git a/src/ralph/dhcp/views.py b/src/ralph/dhcp/views.py index 497e23a9bc..6cac95f86f 100644 --- a/src/ralph/dhcp/views.py +++ b/src/ralph/dhcp/views.py @@ -5,7 +5,7 @@ HttpResponse, HttpResponseBadRequest, HttpResponseNotFound, - HttpResponseNotModified, + HttpResponseNotModified ) from django.utils.http import http_date, parse_http_date_safe from django.views.generic.base import TemplateView @@ -16,7 +16,11 @@ from ralph.data_center.models import DataCenter from ralph.deployment.models import Deployment from ralph.dhcp.models import DHCPEntry, DHCPServer, DNSServer -from ralph.networks.models.networks import IPAddress, Network, NetworkEnvironment +from ralph.networks.models.networks import ( + IPAddress, + Network, + NetworkEnvironment +) logger = logging.getLogger(__name__) diff --git a/src/ralph/dns/tests.py b/src/ralph/dns/tests.py index 69483c384a..6112916a22 100644 --- a/src/ralph/dns/tests.py +++ b/src/ralph/dns/tests.py @@ -2,14 +2,21 @@ from unittest.mock import patch from django.db import transaction -from django.test import TestCase, TransactionTestCase, override_settings +from django.test import override_settings, TestCase, TransactionTestCase -from ralph.assets.tests.factories import ConfigurationClassFactory, EthernetFactory +from ralph.assets.tests.factories import ( + ConfigurationClassFactory, + EthernetFactory +) from ralph.data_center.models import BaseObjectCluster, DataCenterAsset from ralph.dns.dnsaas import DNSaaS from ralph.dns.forms import DNSRecordForm, RecordType from ralph.dns.publishers import _get_txt_data_to_publish_to_dnsaas -from ralph.dns.views import DNSaaSIntegrationNotEnabledError, DNSView, add_errors +from ralph.dns.views import ( + add_errors, + DNSaaSIntegrationNotEnabledError, + DNSView +) from ralph.networks.tests.factories import IPAddressFactory from ralph.virtual.models import VirtualServer from ralph.virtual.tests.factories import VirtualServerFactory diff --git a/src/ralph/domains/admin.py b/src/ralph/domains/admin.py index bd6d41ab0e..64582f4d99 100644 --- a/src/ralph/domains/admin.py +++ b/src/ralph/domains/admin.py @@ -14,7 +14,7 @@ DomainCategory, DomainContract, DomainProviderAdditionalServices, - DomainRegistrant, + DomainRegistrant ) diff --git a/src/ralph/domains/models/domains.py b/src/ralph/domains/models/domains.py index 4ffdf2f18c..9b847a4a77 100644 --- a/src/ralph/domains/models/domains.py +++ b/src/ralph/domains/models/domains.py @@ -12,7 +12,7 @@ AdminAbsoluteUrlMixin, NamedMixin, PriceMixin, - TimeStampMixin, + TimeStampMixin ) from ralph.lib.permissions.models import PermByFieldMixin diff --git a/src/ralph/domains/tests/factories.py b/src/ralph/domains/tests/factories.py index 8ef0008251..8465cbd421 100644 --- a/src/ralph/domains/tests/factories.py +++ b/src/ralph/domains/tests/factories.py @@ -10,7 +10,7 @@ DomainCategory, DomainContract, DomainRegistrant, - DomainStatus, + DomainStatus ) from ralph.domains.models.domains import DomainProviderAdditionalServices diff --git a/src/ralph/helpers.py b/src/ralph/helpers.py index 2dd2673ff0..a26ec0a719 100644 --- a/src/ralph/helpers.py +++ b/src/ralph/helpers.py @@ -3,7 +3,7 @@ from functools import wraps from django.conf import settings -from django.core.cache import DEFAULT_CACHE_ALIAS, caches +from django.core.cache import caches, DEFAULT_CACHE_ALIAS from django.http import HttpResponse logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/custom_fields/admin.py b/src/ralph/lib/custom_fields/admin.py index 74f7a3cf49..e5ea708cca 100644 --- a/src/ralph/lib/custom_fields/admin.py +++ b/src/ralph/lib/custom_fields/admin.py @@ -8,7 +8,7 @@ from ralph.lib.custom_fields.forms import ( CustomFieldValueForm, CustomFieldValueFormSet, - CustomFieldValueWithClearChildrenForm, + CustomFieldValueWithClearChildrenForm ) from ralph.lib.custom_fields.models import CustomField, CustomFieldValue from ralph.lib.custom_fields.views import CustomFieldFormfieldView diff --git a/src/ralph/lib/custom_fields/api/serializers.py b/src/ralph/lib/custom_fields/api/serializers.py index c2eeb67b97..bb24f3f95f 100644 --- a/src/ralph/lib/custom_fields/api/serializers.py +++ b/src/ralph/lib/custom_fields/api/serializers.py @@ -4,7 +4,7 @@ from ralph.api.serializers import ( AdditionalLookupRelatedField, RalphAPISaveSerializer, - RalphAPISerializer, + RalphAPISerializer ) from ..models import CustomField, CustomFieldValue diff --git a/src/ralph/lib/custom_fields/api/viewsets.py b/src/ralph/lib/custom_fields/api/viewsets.py index 7601b17b1d..d22e4dea22 100644 --- a/src/ralph/lib/custom_fields/api/viewsets.py +++ b/src/ralph/lib/custom_fields/api/viewsets.py @@ -4,7 +4,10 @@ from rest_framework.status import HTTP_403_FORBIDDEN from ..models import CustomFieldValue -from .serializers import CustomFieldValueSaveSerializer, CustomFieldValueSerializer +from .serializers import ( + CustomFieldValueSaveSerializer, + CustomFieldValueSerializer +) class ObjectCustomFieldsViewSet(viewsets.ModelViewSet): diff --git a/src/ralph/lib/custom_fields/fields.py b/src/ralph/lib/custom_fields/fields.py index 4aae85417b..8617569d91 100644 --- a/src/ralph/lib/custom_fields/fields.py +++ b/src/ralph/lib/custom_fields/fields.py @@ -4,8 +4,8 @@ from typing import Any from django.contrib.contenttypes.fields import ( - GenericRelation, create_generic_related_manager, + GenericRelation ) from django.contrib.contenttypes.models import ContentType from django.db import models diff --git a/src/ralph/lib/custom_fields/forms.py b/src/ralph/lib/custom_fields/forms.py index 51e6319827..ea97ca5034 100644 --- a/src/ralph/lib/custom_fields/forms.py +++ b/src/ralph/lib/custom_fields/forms.py @@ -3,8 +3,8 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db.models import Q -from django.utils.translation import ugettext from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext class CustomFieldValueForm(forms.ModelForm): diff --git a/src/ralph/lib/custom_fields/models.py b/src/ralph/lib/custom_fields/models.py index ea6bbd7946..0b50f4ce84 100644 --- a/src/ralph/lib/custom_fields/models.py +++ b/src/ralph/lib/custom_fields/models.py @@ -14,7 +14,10 @@ from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin -from .fields import CustomFieldsWithInheritanceRelation, CustomFieldValueQuerySet +from .fields import ( + CustomFieldsWithInheritanceRelation, + CustomFieldValueQuerySet +) logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/custom_fields/tests/api.py b/src/ralph/lib/custom_fields/tests/api.py index 202228d73d..cf361d9ecf 100644 --- a/src/ralph/lib/custom_fields/tests/api.py +++ b/src/ralph/lib/custom_fields/tests/api.py @@ -4,7 +4,7 @@ from ..api import ( CustomFieldsFilterBackend, NestedCustomFieldsRouterMixin, - WithCustomFieldsSerializerMixin, + WithCustomFieldsSerializerMixin ) from .models import SomeModel diff --git a/src/ralph/lib/custom_fields/tests/factories.py b/src/ralph/lib/custom_fields/tests/factories.py index 68295f4e07..d584832382 100644 --- a/src/ralph/lib/custom_fields/tests/factories.py +++ b/src/ralph/lib/custom_fields/tests/factories.py @@ -4,7 +4,7 @@ from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue, + CustomFieldValue ) diff --git a/src/ralph/lib/hooks/main.py b/src/ralph/lib/hooks/main.py index 03cac9a87d..b4c6241eec 100644 --- a/src/ralph/lib/hooks/main.py +++ b/src/ralph/lib/hooks/main.py @@ -16,7 +16,7 @@ def hook_name_to_env_name(name, prefix='HOOKS'): @lru_cache.lru_cache(maxsize=None) -def get_hook(name: str, variant: Optional[str]=None) -> Callable[..., Any]: +def get_hook(name: str, variant: Optional[str] = None) -> Callable[..., Any]: """Returns function based on configuration and entry_points.""" loaded_func = None diff --git a/src/ralph/lib/metrics/collector.py b/src/ralph/lib/metrics/collector.py index b60d7f6e81..366c2cb308 100644 --- a/src/ralph/lib/metrics/collector.py +++ b/src/ralph/lib/metrics/collector.py @@ -2,7 +2,7 @@ from contextlib import ContextDecorator from django.conf import settings -from statsd import StatsClient, defaults +from statsd import defaults, StatsClient logger = logging.getLogger(__name__) statsd = None diff --git a/src/ralph/lib/metrics/middlewares.py b/src/ralph/lib/metrics/middlewares.py index 0741ee84b5..b414a649a7 100644 --- a/src/ralph/lib/metrics/middlewares.py +++ b/src/ralph/lib/metrics/middlewares.py @@ -3,7 +3,7 @@ import threading import time from collections import deque -from resource import RUSAGE_SELF, getrusage +from resource import getrusage, RUSAGE_SELF from django.conf import settings from django.db.backends.utils import CursorWrapper diff --git a/src/ralph/lib/mixins/tests/test_api.py b/src/ralph/lib/mixins/tests/test_api.py index ff5f334ed6..53b4e9f5c9 100644 --- a/src/ralph/lib/mixins/tests/test_api.py +++ b/src/ralph/lib/mixins/tests/test_api.py @@ -1,7 +1,7 @@ from django.test import TestCase from rest_framework.exceptions import ValidationError -from ..api import OTHER, ChoiceFieldWithOtherOptionField +from ..api import ChoiceFieldWithOtherOptionField, OTHER class TestChoiceFieldWithOtherOptionSerializer(TestCase): diff --git a/src/ralph/lib/permissions/admin.py b/src/ralph/lib/permissions/admin.py index 0ff3c2b39d..db49348e0d 100644 --- a/src/ralph/lib/permissions/admin.py +++ b/src/ralph/lib/permissions/admin.py @@ -7,7 +7,10 @@ from django.db.models.query import QuerySet from ralph.lib.mixins.forms import RequestFormMixin -from ralph.lib.permissions.models import PermByFieldMixin, PermissionsForObjectMixin +from ralph.lib.permissions.models import ( + PermByFieldMixin, + PermissionsForObjectMixin +) logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/permissions/api.py b/src/ralph/lib/permissions/api.py index c803fce4e5..5aa40f14a7 100644 --- a/src/ralph/lib/permissions/api.py +++ b/src/ralph/lib/permissions/api.py @@ -10,7 +10,10 @@ from rest_framework.filters import BaseFilterBackend from rest_framework.permissions import IsAuthenticated as DRFIsAuthenticated -from ralph.lib.permissions.models import PermByFieldMixin, PermissionsForObjectMixin +from ralph.lib.permissions.models import ( + PermByFieldMixin, + PermissionsForObjectMixin +) ADD_PERM = ['%(app_label)s.add_%(model_name)s'] CHANGE_PERM = ['%(app_label)s.change_%(model_name)s'] diff --git a/src/ralph/lib/permissions/tests/api.py b/src/ralph/lib/permissions/tests/api.py index f765d1928e..ed848461b2 100644 --- a/src/ralph/lib/permissions/tests/api.py +++ b/src/ralph/lib/permissions/tests/api.py @@ -7,9 +7,14 @@ ObjectPermissionsMixin, PermissionsForObjectFilter, PermissionsPerFieldSerializerMixin, - RelatedObjectsPermissionsSerializerMixin, + RelatedObjectsPermissionsSerializerMixin +) +from ralph.lib.permissions.tests.models import ( + Article, + Foo, + Library, + LongArticle ) -from ralph.lib.permissions.tests.models import Article, Foo, Library, LongArticle class Permission(ObjectPermissionsMixin, permissions.IsAuthenticated): diff --git a/src/ralph/lib/permissions/tests/models.py b/src/ralph/lib/permissions/tests/models.py index 32084dbe33..842e25dab9 100644 --- a/src/ralph/lib/permissions/tests/models.py +++ b/src/ralph/lib/permissions/tests/models.py @@ -5,7 +5,7 @@ from ralph.lib.permissions.models import ( PermByFieldMixin, PermissionsForObjectMixin, - user_permission, + user_permission ) diff --git a/src/ralph/lib/permissions/tests/test_permissions_per_object.py b/src/ralph/lib/permissions/tests/test_permissions_per_object.py index 5b6bb23346..c020e14c03 100644 --- a/src/ralph/lib/permissions/tests/test_permissions_per_object.py +++ b/src/ralph/lib/permissions/tests/test_permissions_per_object.py @@ -8,11 +8,11 @@ from ralph.lib.permissions.tests._base import PermissionsTestMixin from ralph.lib.permissions.tests.models import ( Article, - Library, - LongArticle, has_long_title, is_author, is_collabolator, + Library, + LongArticle ) diff --git a/src/ralph/lib/polymorphic/models.py b/src/ralph/lib/polymorphic/models.py index fde3813072..a85d7d1708 100644 --- a/src/ralph/lib/polymorphic/models.py +++ b/src/ralph/lib/polymorphic/models.py @@ -227,7 +227,7 @@ def __iter__(self): try: cache_ = self._my_cache.copy() pks = [pk for pk in self._pks_order] - except AttributeError as e: + except AttributeError: yield from self._result_cache else: for pk in pks: diff --git a/src/ralph/lib/polymorphic/tests/tests_models.py b/src/ralph/lib/polymorphic/tests/tests_models.py index db8b33913c..6f8532681d 100644 --- a/src/ralph/lib/polymorphic/tests/tests_models.py +++ b/src/ralph/lib/polymorphic/tests/tests_models.py @@ -8,7 +8,7 @@ PolymorphicModelTest, PolymorphicModelTest2, SomeM2MModel, - SomethingRelated, + SomethingRelated ) diff --git a/src/ralph/lib/table/table.py b/src/ralph/lib/table/table.py index 5848ffea0e..9d8720b063 100644 --- a/src/ralph/lib/table/table.py +++ b/src/ralph/lib/table/table.py @@ -15,7 +15,7 @@ from ralph.admin.helpers import ( get_field_by_relation_path, get_field_title_by_relation_path, - getattr_dunder, + getattr_dunder ) diff --git a/src/ralph/lib/threadlocal/middleware.py b/src/ralph/lib/threadlocal/middleware.py index 582ac1de16..b61b964b32 100644 --- a/src/ralph/lib/threadlocal/middleware.py +++ b/src/ralph/lib/threadlocal/middleware.py @@ -1,5 +1,6 @@ from django.utils.deprecation import MiddlewareMixin -from threadlocals.middleware import ThreadLocalMiddleware as ThreadLocalMiddleware_ +from threadlocals.middleware import \ + ThreadLocalMiddleware as ThreadLocalMiddleware_ class ThreadLocalMiddleware(ThreadLocalMiddleware_, MiddlewareMixin): diff --git a/src/ralph/lib/transitions/admin.py b/src/ralph/lib/transitions/admin.py index d40550c285..4ab3607d53 100644 --- a/src/ralph/lib/transitions/admin.py +++ b/src/ralph/lib/transitions/admin.py @@ -14,7 +14,11 @@ from ralph.admin.views.extra import RalphDetailView from ralph.helpers import get_model_view_url_name from ralph.lib.transitions.forms import TransitionForm -from ralph.lib.transitions.models import Transition, TransitionJob, TransitionModel +from ralph.lib.transitions.models import ( + Transition, + TransitionJob, + TransitionModel +) from ralph.lib.transitions.views import RunBulkTransitionView, RunTransitionView diff --git a/src/ralph/lib/transitions/api/routers.py b/src/ralph/lib/transitions/api/routers.py index d7f2a294d8..9cad70ee13 100644 --- a/src/ralph/lib/transitions/api/routers.py +++ b/src/ralph/lib/transitions/api/routers.py @@ -10,7 +10,7 @@ TransitionModelViewSet, TransitionsHistoryViewSet, TransitionView, - TransitionViewSet, + TransitionViewSet ) router.register(r'transitions', TransitionViewSet) diff --git a/src/ralph/lib/transitions/api/serializers.py b/src/ralph/lib/transitions/api/serializers.py index b437b2376d..cf7ffe3ffc 100644 --- a/src/ralph/lib/transitions/api/serializers.py +++ b/src/ralph/lib/transitions/api/serializers.py @@ -8,7 +8,7 @@ Transition, TransitionJob, TransitionModel, - TransitionsHistory, + TransitionsHistory ) diff --git a/src/ralph/lib/transitions/api/views.py b/src/ralph/lib/transitions/api/views.py index 2ecae10704..9ce93c9686 100644 --- a/src/ralph/lib/transitions/api/views.py +++ b/src/ralph/lib/transitions/api/views.py @@ -5,8 +5,8 @@ from django.core.exceptions import ObjectDoesNotExist from django.urls import reverse from rest_framework import serializers, status -from rest_framework.exceptions import NotFound from rest_framework.exceptions import ValidationError as DRFValidationError +from rest_framework.exceptions import NotFound from rest_framework.response import Response from rest_framework.settings import api_settings from rest_framework.views import APIView @@ -20,20 +20,20 @@ TransitionJobSerializer, TransitionModelSerializer, TransitionSerializer, - TransitionsHistorySerializer, + TransitionsHistorySerializer ) from ralph.lib.transitions.exceptions import TransitionNotAllowedError from ralph.lib.transitions.models import ( + _check_instances_for_transition, + _transition_data_validation, Action, + run_transition, Transition, TransitionJob, TransitionModel, - TransitionsHistory, - _check_instances_for_transition, - _transition_data_validation, - run_transition, + TransitionsHistory ) -from ralph.lib.transitions.views import NonAtomicView, collect_actions +from ralph.lib.transitions.views import collect_actions, NonAtomicView FIELD_MAP = { forms.CharField: (serializers.CharField, [ diff --git a/src/ralph/lib/transitions/async.py b/src/ralph/lib/transitions/async.py index 41c39eb1d6..679154062b 100644 --- a/src/ralph/lib/transitions/async.py +++ b/src/ralph/lib/transitions/async.py @@ -11,17 +11,17 @@ FailedActionError, FreezeAsyncTransition, MoreThanOneStartedActionError, - RescheduleAsyncTransitionActionLater, + RescheduleAsyncTransitionActionLater ) from ralph.lib.transitions.models import ( - TransitionJob, - TransitionJobAction, - TransitionJobActionStatus, _check_action_with_instances, _check_instances_for_transition, _order_actions_by_requirements, _post_transition_instance_processing, _prepare_action_data, + TransitionJob, + TransitionJobAction, + TransitionJobActionStatus ) logger = logging.getLogger(__name__) @@ -129,7 +129,7 @@ def _perform_async_transition(transition_job): tja=tja, **defaults ) - except RescheduleAsyncTransitionActionLater as e: + except RescheduleAsyncTransitionActionLater: # action is not ready - reschedule this job later and # continue when you left off transition_job.reschedule() diff --git a/src/ralph/lib/transitions/checks.py b/src/ralph/lib/transitions/checks.py index 843d43e328..6fdf8f4b4d 100644 --- a/src/ralph/lib/transitions/checks.py +++ b/src/ralph/lib/transitions/checks.py @@ -2,7 +2,7 @@ from django.core.checks import Error from django.db.utils import DatabaseError -from django.template.loader import TemplateDoesNotExist, get_template +from django.template.loader import get_template, TemplateDoesNotExist logger = logging.getLogger(__name__) diff --git a/src/ralph/lib/transitions/forms.py b/src/ralph/lib/transitions/forms.py index b31d50202f..220d811820 100644 --- a/src/ralph/lib/transitions/forms.py +++ b/src/ralph/lib/transitions/forms.py @@ -6,10 +6,10 @@ from django.utils.translation import ugettext_lazy as _ from ralph.lib.transitions.models import ( - TRANSITION_ORIGINAL_STATUS, Action, Transition, - TransitionModel, + TRANSITION_ORIGINAL_STATUS, + TransitionModel ) TRANSITION_TEMPLATES = settings.TRANSITION_TEMPLATES diff --git a/src/ralph/lib/transitions/models.py b/src/ralph/lib/transitions/models.py index aa34ef0a32..1a727a3861 100644 --- a/src/ralph/lib/transitions/models.py +++ b/src/ralph/lib/transitions/models.py @@ -13,7 +13,12 @@ from django.core.exceptions import FieldDoesNotExist, ValidationError from django.db import models, transaction from django.db.models.base import ModelBase -from django.db.models.signals import post_delete, post_migrate, post_save, pre_save +from django.db.models.signals import ( + post_delete, + post_migrate, + post_save, + pre_save +) from django.dispatch import receiver from django.utils.functional import curry from django.utils.text import slugify @@ -21,9 +26,16 @@ from django_extensions.db.fields.json import JSONField from reversion import revisions as reversion -from ralph.admin.helpers import get_content_type_for_model, get_field_by_relation_path +from ralph.admin.helpers import ( + get_content_type_for_model, + get_field_by_relation_path +) from ralph.attachments.models import Attachment -from ralph.lib.external_services.models import JOB_NOT_ENDED_STATUSES, Job, JobQuerySet +from ralph.lib.external_services.models import ( + Job, + JOB_NOT_ENDED_STATUSES, + JobQuerySet +) from ralph.lib.metrics import statsd from ralph.lib.mixins.fields import NullableCharField from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin @@ -31,16 +43,16 @@ from ralph.lib.transitions.conf import ( DEFAULT_ASYNC_TRANSITION_SERVICE_NAME, TRANSITION_ATTR_TAG, - TRANSITION_ORIGINAL_STATUS, + TRANSITION_ORIGINAL_STATUS ) from ralph.lib.transitions.exceptions import ( TransitionModelNotFoundError, - TransitionNotAllowedError, + TransitionNotAllowedError ) from ralph.lib.transitions.fields import TransitionField from ralph.lib.transitions.utils import ( _compare_instances_types, - _sort_graph_topologically, + _sort_graph_topologically ) _transitions_fields = {} diff --git a/src/ralph/lib/transitions/templatetags/transitions_tags.py b/src/ralph/lib/transitions/templatetags/transitions_tags.py index fd92f53d14..bd1b84c8ac 100644 --- a/src/ralph/lib/transitions/templatetags/transitions_tags.py +++ b/src/ralph/lib/transitions/templatetags/transitions_tags.py @@ -55,7 +55,7 @@ def history_for_object(parser, token): _, job, obj, _as, var_name = token.split_contents() if _as != 'as': error = True - except: + except: # noqa error = True if error: diff --git a/src/ralph/lib/transitions/tests/factories.py b/src/ralph/lib/transitions/tests/factories.py index 10fda8f78e..dbb8fd5896 100644 --- a/src/ralph/lib/transitions/tests/factories.py +++ b/src/ralph/lib/transitions/tests/factories.py @@ -11,7 +11,7 @@ Transition, TransitionJob, TransitionModel, - TransitionsHistory, + TransitionsHistory ) diff --git a/src/ralph/lib/transitions/tests/test_actions.py b/src/ralph/lib/transitions/tests/test_actions.py index 88e82d1f89..72809935ea 100644 --- a/src/ralph/lib/transitions/tests/test_actions.py +++ b/src/ralph/lib/transitions/tests/test_actions.py @@ -12,11 +12,14 @@ from ralph.back_office.tests.factories import ( BackOfficeAssetFactory, OfficeInfrastructureFactory, - WarehouseFactory, + WarehouseFactory ) from ralph.lib.external_services.models import JobStatus from ralph.lib.transitions.models import TransitionJob, TransitionsHistory -from ralph.lib.transitions.tests import TransitionTestCase, TransitionTestCaseMixin +from ralph.lib.transitions.tests import ( + TransitionTestCase, + TransitionTestCaseMixin +) from ralph.licences.tests.factories import LicenceFactory diff --git a/src/ralph/lib/transitions/tests/test_async.py b/src/ralph/lib/transitions/tests/test_async.py index 858165287e..0df8a5e9b4 100644 --- a/src/ralph/lib/transitions/tests/test_async.py +++ b/src/ralph/lib/transitions/tests/test_async.py @@ -6,9 +6,9 @@ from ralph.lib.external_services.models import JobStatus from ralph.lib.transitions.models import ( - TransitionJob, - TransitionsHistory, run_transition, + TransitionJob, + TransitionsHistory ) from ralph.lib.transitions.tests import TransitionTestCaseMixin from ralph.tests.models import AsyncOrder, Foo, OrderStatus diff --git a/src/ralph/lib/transitions/tests/test_models.py b/src/ralph/lib/transitions/tests/test_models.py index 9d86523933..5907a2607b 100644 --- a/src/ralph/lib/transitions/tests/test_models.py +++ b/src/ralph/lib/transitions/tests/test_models.py @@ -6,14 +6,14 @@ from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.exceptions import ( TransitionModelNotFoundError, - TransitionNotAllowedError, + TransitionNotAllowedError ) from ralph.lib.transitions.models import ( - Transition, - TransitionModel, _check_and_get_transition, _create_graph_from_actions, run_field_transition, + Transition, + TransitionModel ) from ralph.lib.transitions.tests import TransitionTestCase from ralph.tests.models import Foo, Order, OrderStatus diff --git a/src/ralph/lib/transitions/tests/test_utils.py b/src/ralph/lib/transitions/tests/test_utils.py index 50f3e98f58..3ef95b8454 100644 --- a/src/ralph/lib/transitions/tests/test_utils.py +++ b/src/ralph/lib/transitions/tests/test_utils.py @@ -1,6 +1,6 @@ from django.test import TestCase -from ralph.lib.transitions.utils import CycleError, _sort_graph_topologically +from ralph.lib.transitions.utils import _sort_graph_topologically, CycleError class TopologicalSortTest(TestCase): diff --git a/src/ralph/lib/transitions/urls.py b/src/ralph/lib/transitions/urls.py index ed2718a400..854d461a4a 100644 --- a/src/ralph/lib/transitions/urls.py +++ b/src/ralph/lib/transitions/urls.py @@ -2,7 +2,7 @@ from ralph.lib.transitions.views import ( AsyncBulkTransitionsAwaiterView, - KillTransitionJobView, + KillTransitionJobView ) urlpatterns = [ diff --git a/src/ralph/lib/transitions/views.py b/src/ralph/lib/transitions/views.py index 542d9a6c9e..ea071a7357 100644 --- a/src/ralph/lib/transitions/views.py +++ b/src/ralph/lib/transitions/views.py @@ -9,7 +9,7 @@ Http404, HttpResponseBadRequest, HttpResponseForbidden, - HttpResponseRedirect, + HttpResponseRedirect ) from django.shortcuts import get_object_or_404 from django.urls import reverse @@ -27,11 +27,11 @@ from ralph.lib.permissions.views import PermissionViewMetaClass from ralph.lib.transitions.exceptions import TransitionNotAllowedError from ralph.lib.transitions.models import ( - Transition, - TransitionJob, _check_instances_for_transition, _transition_data_validation, run_transition, + Transition, + TransitionJob ) diff --git a/src/ralph/licences/admin.py b/src/ralph/licences/admin.py index 2d5158413a..5423ee2bc2 100644 --- a/src/ralph/licences/admin.py +++ b/src/ralph/licences/admin.py @@ -3,7 +3,11 @@ from ralph.admin.decorators import register from ralph.admin.filters import TagsListFilter -from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphTabularInline +from ralph.admin.mixins import ( + BulkEditChangeListMixin, + RalphAdmin, + RalphTabularInline +) from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.assets.invoice_report import InvoiceReportMixin from ralph.attachments.admin import AttachmentsMixin @@ -15,7 +19,7 @@ Licence, LicenceType, LicenceUser, - Software, + Software ) diff --git a/src/ralph/licences/api.py b/src/ralph/licences/api.py index 78cbdf2fb3..9328dbe9da 100644 --- a/src/ralph/licences/api.py +++ b/src/ralph/licences/api.py @@ -5,7 +5,7 @@ from ralph.api.serializers import ReversionHistoryAPISerializerMixin from ralph.assets.api.serializers import ( BaseObjectSimpleSerializer, - ServiceEnvironmentSimpleSerializer, + ServiceEnvironmentSimpleSerializer ) from ralph.lib.api.utils import renderer_classes_without_form from ralph.licences.models import ( @@ -13,7 +13,7 @@ Licence, LicenceType, LicenceUser, - Software, + Software ) diff --git a/src/ralph/licences/models.py b/src/ralph/licences/models.py index c0c75e4ce6..2f4a10f52e 100644 --- a/src/ralph/licences/models.py +++ b/src/ralph/licences/models.py @@ -15,10 +15,15 @@ from ralph.assets.models.base import BaseObject from ralph.assets.models.choices import ObjectModelType from ralph.lib.mixins.fields import BaseObjectForeignKey -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, PriceMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + PriceMixin +) from ralph.lib.permissions.models import PermByFieldMixin from ralph.lib.polymorphic.models import PolymorphicQuerySet + _SELECT_USED_LICENCES_QUERY = """ SELECT COALESCE(SUM({assignment_table}.{quantity_column}), 0) FROM {assignment_table} diff --git a/src/ralph/licences/tests/factories.py b/src/ralph/licences/tests/factories.py index e6c1dd9b98..1e139da1dc 100644 --- a/src/ralph/licences/tests/factories.py +++ b/src/ralph/licences/tests/factories.py @@ -13,11 +13,11 @@ from ralph.assets.tests.factories import ( AssetHolderFactory, BudgetInfoFactory, - ManufacturerFactory, + ManufacturerFactory ) from ralph.back_office.tests.factories import ( BackOfficeAssetFactory, - OfficeInfrastructureFactory, + OfficeInfrastructureFactory ) from ralph.data_center.tests.factories import DataCenterAssetFactory from ralph.licences.models import ( @@ -25,7 +25,7 @@ Licence, LicenceType, LicenceUser, - Software, + Software ) date_now = datetime.now().date() diff --git a/src/ralph/networks/admin.py b/src/ralph/networks/admin.py index 12cedfc639..ae75c6defe 100644 --- a/src/ralph/networks/admin.py +++ b/src/ralph/networks/admin.py @@ -18,14 +18,14 @@ ContainsIPAddressFilter, IPRangeFilter, NetworkClassFilter, - NetworkRangeFilter, + NetworkRangeFilter ) from ralph.networks.models.networks import ( DiscoveryQueue, IPAddress, Network, NetworkEnvironment, - NetworkKind, + NetworkKind ) @@ -163,8 +163,8 @@ class NetworkAdmin(RalphMPTTAdmin): add_message = _('Network added to {}') change_message = _( - 'Network reassigned from network {} to {}' - ) # noqa + 'Network reassigned from network {} to {}' # noqa + ) fieldsets = ( ( @@ -343,8 +343,8 @@ class IPAddressAdmin(ParentChangeMixin, RalphAdmin): add_message = _('IP added to {}') change_message = _( - 'IP reassigned from network {} to {}' - ) # noqa + 'IP reassigned from network {} to {}' # noqa + ) @mark_safe def get_network_path(self, obj): diff --git a/src/ralph/networks/api.py b/src/ralph/networks/api.py index 71372ee556..2bec7d2299 100644 --- a/src/ralph/networks/api.py +++ b/src/ralph/networks/api.py @@ -5,7 +5,12 @@ from ralph.api import RalphAPISerializer, RalphAPIViewSet, router from ralph.api.serializers import RalphAPISaveSerializer from ralph.assets.api.serializers import EthernetSerializer -from ralph.networks.models import IPAddress, Network, NetworkEnvironment, NetworkKind +from ralph.networks.models import ( + IPAddress, + Network, + NetworkEnvironment, + NetworkKind +) class NetworkEnvironmentSerializer(RalphAPISerializer): diff --git a/src/ralph/networks/filters.py b/src/ralph/networks/filters.py index 033d0dd7d7..7b7a4d27dd 100644 --- a/src/ralph/networks/filters.py +++ b/src/ralph/networks/filters.py @@ -7,9 +7,9 @@ from django.utils.translation import ugettext_lazy as _ from ralph.admin.filters import ( - SEARCH_OR_SEPARATORS_REGEX, ChoicesListFilter, - TextListFilter, + SEARCH_OR_SEPARATORS_REGEX, + TextListFilter ) PRIVATE_NETWORK_CIDRS = [ diff --git a/src/ralph/networks/models/networks.py b/src/ralph/networks/models/networks.py index 17aa936057..2ecaca7bca 100644 --- a/src/ralph/networks/models/networks.py +++ b/src/ralph/networks/models/networks.py @@ -16,13 +16,16 @@ from ralph.assets.models import AssetLastHostname, Ethernet from ralph.dns.dnsaas import DNSaaS from ralph.lib import network as network_tools -from ralph.lib.mixins.fields import NullableCharField, NullableCharFieldWithAutoStrip +from ralph.lib.mixins.fields import ( + NullableCharField, + NullableCharFieldWithAutoStrip +) from ralph.lib.mixins.models import ( AdminAbsoluteUrlMixin, LastSeenMixin, NamedMixin, PreviousStateMixin, - TimeStampMixin, + TimeStampMixin ) from ralph.lib.polymorphic.fields import PolymorphicManyToManyField from ralph.networks.fields import IPNetwork diff --git a/src/ralph/networks/tests/factories.py b/src/ralph/networks/tests/factories.py index 46e619c20f..eaf4c7ea50 100644 --- a/src/ralph/networks/tests/factories.py +++ b/src/ralph/networks/tests/factories.py @@ -10,7 +10,7 @@ IPAddress, Network, NetworkEnvironment, - NetworkKind, + NetworkKind ) diff --git a/src/ralph/networks/tests/test_forms.py b/src/ralph/networks/tests/test_forms.py index 60d8ff15c9..794577066e 100755 --- a/src/ralph/networks/tests/test_forms.py +++ b/src/ralph/networks/tests/test_forms.py @@ -7,7 +7,7 @@ from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory, + NetworkFactory ) from ralph.tests import RalphTestCase from ralph.tests.models import PolymorphicTestModel diff --git a/src/ralph/networks/tests/test_models.py b/src/ralph/networks/tests/test_models.py index f61a383101..c1ee969e46 100644 --- a/src/ralph/networks/tests/test_models.py +++ b/src/ralph/networks/tests/test_models.py @@ -4,7 +4,7 @@ from ddt import data, ddt, unpack from django.core.exceptions import ValidationError from django.db.models import F -from django.test import RequestFactory, override_settings +from django.test import override_settings, RequestFactory from ralph.admin.helpers import CastToInteger from ralph.assets.models import AssetLastHostname @@ -12,7 +12,7 @@ from ralph.data_center.tests.factories import ( ClusterFactory, DataCenterAssetFactory, - DataCenterFactory, + DataCenterFactory ) from ralph.networks.admin import NetworkAdmin from ralph.networks.filters import NetworkClassFilter @@ -20,7 +20,7 @@ from ralph.networks.tests.factories import ( IPAddressFactory, NetworkEnvironmentFactory, - NetworkFactory, + NetworkFactory ) from ralph.tests import RalphTestCase from ralph.virtual.tests.factories import VirtualServerFactory diff --git a/src/ralph/notifications/test_notification.py b/src/ralph/notifications/test_notification.py index 70a631ace1..f8cf649bd1 100644 --- a/src/ralph/notifications/test_notification.py +++ b/src/ralph/notifications/test_notification.py @@ -4,7 +4,10 @@ from django.test import TransactionTestCase from ralph.accounts.tests.factories import UserFactory -from ralph.assets.tests.factories import ServiceEnvironmentFactory, ServiceFactory +from ralph.assets.tests.factories import ( + ServiceEnvironmentFactory, + ServiceFactory +) from ralph.data_center.models import DataCenterAsset from ralph.data_center.tests.factories import DataCenterAssetFactory diff --git a/src/ralph/operations/admin.py b/src/ralph/operations/admin.py index f3628e8eba..74e6c41600 100644 --- a/src/ralph/operations/admin.py +++ b/src/ralph/operations/admin.py @@ -21,7 +21,7 @@ Operation, OperationStatus, OperationType, - Problem, + Problem ) diff --git a/src/ralph/operations/changemanagement/jira.py b/src/ralph/operations/changemanagement/jira.py index 09bf46a267..0741c9601b 100644 --- a/src/ralph/operations/changemanagement/jira.py +++ b/src/ralph/operations/changemanagement/jira.py @@ -62,5 +62,5 @@ def _safe_load_datetime(event_data, field): return ( parse_datetime(datetime_str).astimezone(timezone.utc).replace(tzinfo=None) ) - except: + except: # noqa return None diff --git a/src/ralph/operations/models.py b/src/ralph/operations/models.py index 7fdb4269c8..1781fa94d5 100644 --- a/src/ralph/operations/models.py +++ b/src/ralph/operations/models.py @@ -11,7 +11,11 @@ from ralph.assets.models.base import BaseObject from ralph.lib.mixins.fields import TicketIdField -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TaggableMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + TaggableMixin +) from ralph.lib.polymorphic.fields import PolymorphicManyToManyField diff --git a/src/ralph/operations/tests/factories.py b/src/ralph/operations/tests/factories.py index 4110c31936..8faacc5a0b 100644 --- a/src/ralph/operations/tests/factories.py +++ b/src/ralph/operations/tests/factories.py @@ -11,7 +11,7 @@ Operation, OperationStatus, OperationType, - Problem, + Problem ) diff --git a/src/ralph/reports/helpers.py b/src/ralph/reports/helpers.py index 765f4ca305..b3d98ed1b7 100644 --- a/src/ralph/reports/helpers.py +++ b/src/ralph/reports/helpers.py @@ -32,13 +32,16 @@ def generate_report(name, requester, instances, language, context): json.dumps( { "id": ", ".join( - [str(obj.id) for obj in instances[n : n + items_per_attachment]] + [ + str(obj.id) for obj in + instances[n:n + items_per_attachment] + ] ), "now": str(datetime.datetime.now()), "logged_user": obj_to_dict(requester), "affected_user": obj_to_dict(instances[0].user), "owner": obj_to_dict(instances[0].owner), - "assets": context[n : n + items_per_attachment], + "assets": context[n:n + items_per_attachment], } ) ) diff --git a/src/ralph/reports/models.py b/src/ralph/reports/models.py index 6ef9ffccf4..0439cc510c 100644 --- a/src/ralph/reports/models.py +++ b/src/ralph/reports/models.py @@ -3,7 +3,11 @@ from django.utils.translation import ugettext_lazy as _ from ralph.attachments.helpers import get_file_path -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + TimeStampMixin +) def get_report_file_path(instance, filename): diff --git a/src/ralph/reports/resources.py b/src/ralph/reports/resources.py index cc3efe629c..6e3cd824b3 100644 --- a/src/ralph/reports/resources.py +++ b/src/ralph/reports/resources.py @@ -5,7 +5,11 @@ from import_export.resources import ModelResource from import_export.widgets import Widget -from ralph.data_center.models import DataCenterAsset, Orientation, RackOrientation +from ralph.data_center.models import ( + DataCenterAsset, + Orientation, + RackOrientation +) class ChoiceWidget(Widget): diff --git a/src/ralph/reports/tests/test_reports.py b/src/ralph/reports/tests/test_reports.py index 79ba14d905..74f0537f34 100644 --- a/src/ralph/reports/tests/test_reports.py +++ b/src/ralph/reports/tests/test_reports.py @@ -8,7 +8,7 @@ from ralph.assets.tests.factories import ( CategoryFactory, DataCenterAssetModelFactory, - ManufacturerFactory, + ManufacturerFactory ) from ralph.attachments.models import Attachment, AttachmentItem from ralph.back_office.models import BackOfficeAsset @@ -18,7 +18,7 @@ from ralph.licences.models import BaseObjectLicence from ralph.licences.tests.factories import ( LicenceFactory, - LicenceWithUserAndBaseObjectsFactory, + LicenceWithUserAndBaseObjectsFactory ) from ralph.reports.models import ReportLanguage from ralph.reports.views import ( @@ -26,7 +26,7 @@ AssetSupportsReport, CategoryModelReport, CategoryModelStatusReport, - LicenceRelationsReport, + LicenceRelationsReport ) from ralph.supports.models import BaseObjectsSupport from ralph.supports.tests.factories import SupportFactory diff --git a/src/ralph/reports/tests/test_resources.py b/src/ralph/reports/tests/test_resources.py index 1849935c63..24dc94b2d8 100644 --- a/src/ralph/reports/tests/test_resources.py +++ b/src/ralph/reports/tests/test_resources.py @@ -1,8 +1,14 @@ from random import randint -from ralph.assets.tests.factories import DataCenterAssetModelFactory, EthernetFactory +from ralph.assets.tests.factories import ( + DataCenterAssetModelFactory, + EthernetFactory +) from ralph.data_center.models import Orientation, RackOrientation -from ralph.data_center.tests.factories import DataCenterAssetFactory, RackFactory +from ralph.data_center.tests.factories import ( + DataCenterAssetFactory, + RackFactory +) from ralph.networks.tests.factories import IPAddressFactory from ralph.reports.resources import DataCenterAssetTextResource from ralph.tests import RalphTestCase diff --git a/src/ralph/security/api.py b/src/ralph/security/api.py index 12ed432917..97df94014c 100644 --- a/src/ralph/security/api.py +++ b/src/ralph/security/api.py @@ -8,7 +8,7 @@ from ralph.api import RalphAPISerializer, RalphAPIViewSet, router from ralph.api.serializers import RalphAPISaveSerializer from ralph.networks.models.networks import IPAddress -from ralph.security.models import SecurityScan, Vulnerability, any_exceeded +from ralph.security.models import any_exceeded, SecurityScan, Vulnerability class VulnerabilitySerializer(RalphAPISerializer): diff --git a/src/ralph/security/models.py b/src/ralph/security/models.py index a7d94b585b..2a9edee7ef 100644 --- a/src/ralph/security/models.py +++ b/src/ralph/security/models.py @@ -6,7 +6,11 @@ from django.utils.translation import ugettext_lazy as _ from ralph.assets.models.base import BaseObject -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TaggableMixin, TimeStampMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + TaggableMixin, + TimeStampMixin +) from ralph.lib.permissions.models import PermByFieldMixin diff --git a/src/ralph/security/tests/test_api.py b/src/ralph/security/tests/test_api.py index f7a6499411..00dfcd0285 100644 --- a/src/ralph/security/tests/test_api.py +++ b/src/ralph/security/tests/test_api.py @@ -7,7 +7,10 @@ from ralph.api.tests._base import RalphAPITestCase from ralph.networks.tests.factories import IPAddressFactory from ralph.security.models import Risk, ScanStatus, SecurityScan, Vulnerability -from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory +from ralph.security.tests.factories import ( + SecurityScanFactory, + VulnerabilityFactory +) class SecurityScanAPITests(RalphAPITestCase): diff --git a/src/ralph/security/tests/test_serializers.py b/src/ralph/security/tests/test_serializers.py index d14610b74b..94b533e262 100644 --- a/src/ralph/security/tests/test_serializers.py +++ b/src/ralph/security/tests/test_serializers.py @@ -4,7 +4,10 @@ from ralph.api.tests._base import RalphAPITestCase from ralph.networks.tests.factories import IPAddressFactory from ralph.security.api import SaveSecurityScanSerializer -from ralph.security.tests.factories import SecurityScanFactory, VulnerabilityFactory +from ralph.security.tests.factories import ( + SecurityScanFactory, + VulnerabilityFactory +) class SaveSecurityScanSerializerTests(RalphAPITestCase): diff --git a/src/ralph/settings/prod.py b/src/ralph/settings/prod.py index d1d02bed15..297251c5a8 100644 --- a/src/ralph/settings/prod.py +++ b/src/ralph/settings/prod.py @@ -44,8 +44,8 @@ CACHES = { "default": { "OPTIONS": ( - json.loads(os.environ.get("REDIS_CACHE_OPTIONS", "{}")) - or DEFAULT_CACHE_OPTIONS + json.loads( + os.environ.get("REDIS_CACHE_OPTIONS", "{}")) or DEFAULT_CACHE_OPTIONS ), }, } diff --git a/src/ralph/sim_cards/admin.py b/src/ralph/sim_cards/admin.py index 0b1d1ecd24..b02d9a3084 100644 --- a/src/ralph/sim_cards/admin.py +++ b/src/ralph/sim_cards/admin.py @@ -1,7 +1,11 @@ from django.utils.translation import ugettext_lazy as _ from ralph.admin.decorators import register -from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphAdminMixin +from ralph.admin.mixins import ( + BulkEditChangeListMixin, + RalphAdmin, + RalphAdminMixin +) from ralph.admin.views.multiadd import MulitiAddAdminMixin from ralph.lib.transitions.admin import TransitionAdminMixin from ralph.sim_cards.forms import SIMCardForm diff --git a/src/ralph/sim_cards/models.py b/src/ralph/sim_cards/models.py index 122f0cb39e..726f9f1fb1 100644 --- a/src/ralph/sim_cards/models.py +++ b/src/ralph/sim_cards/models.py @@ -8,16 +8,20 @@ from django.core.validators import ( MaxLengthValidator, MinLengthValidator, - RegexValidator, + RegexValidator ) from django.db import models from django.utils.translation import ugettext_lazy as _ from ralph.assets.models import AssetHolder from ralph.attachments.utils import send_transition_attachments_to_user -from ralph.back_office.models import Warehouse, autocomplete_user +from ralph.back_office.models import autocomplete_user, Warehouse from ralph.lib.hooks import get_hook -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + TimeStampMixin +) from ralph.lib.transitions.conf import get_report_name_for_transition_id from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.fields import TransitionField diff --git a/src/ralph/sim_cards/tests/test_admin.py b/src/ralph/sim_cards/tests/test_admin.py index 0939090192..3aa9c932a5 100644 --- a/src/ralph/sim_cards/tests/test_admin.py +++ b/src/ralph/sim_cards/tests/test_admin.py @@ -5,7 +5,7 @@ from ralph.sim_cards.models import SIMCard from ralph.sim_cards.tests.factories import ( CellularCarrierFactory, - SIMCardFeatureFactory, + SIMCardFeatureFactory ) from ralph.tests.base import RalphTestCase from ralph.tests.factories import UserFactory diff --git a/src/ralph/ssl_certificates/tests/factories.py b/src/ralph/ssl_certificates/tests/factories.py index ded2278e77..1d74170241 100644 --- a/src/ralph/ssl_certificates/tests/factories.py +++ b/src/ralph/ssl_certificates/tests/factories.py @@ -3,7 +3,10 @@ import factory from factory.django import DjangoModelFactory -from ralph.assets.tests.factories import ManufacturerFactory, ServiceEnvironmentFactory +from ralph.assets.tests.factories import ( + ManufacturerFactory, + ServiceEnvironmentFactory +) from ralph.ssl_certificates.models import CertificateType, SSLCertificate date_now = datetime.now().date() diff --git a/src/ralph/supports/admin.py b/src/ralph/supports/admin.py index 858455a6f5..3efbf4114c 100644 --- a/src/ralph/supports/admin.py +++ b/src/ralph/supports/admin.py @@ -8,7 +8,11 @@ from ralph.admin.decorators import register from ralph.admin.filters import TagsListFilter from ralph.admin.helpers import generate_html_link -from ralph.admin.mixins import BulkEditChangeListMixin, RalphAdmin, RalphTabularInline +from ralph.admin.mixins import ( + BulkEditChangeListMixin, + RalphAdmin, + RalphTabularInline +) from ralph.admin.views.extra import RalphDetailViewAdmin from ralph.attachments.admin import AttachmentsMixin from ralph.data_importer import resources diff --git a/src/ralph/supports/api.py b/src/ralph/supports/api.py index 3c091980ca..a32426fdf0 100644 --- a/src/ralph/supports/api.py +++ b/src/ralph/supports/api.py @@ -6,7 +6,7 @@ from ralph.assets.api.serializers import ( ServiceEnvironmentSimpleSerializer, StrField, - TypeFromContentTypeSerializerMixin, + TypeFromContentTypeSerializerMixin ) from ralph.assets.models import BaseObject from ralph.supports.models import BaseObjectsSupport, Support, SupportType diff --git a/src/ralph/supports/models.py b/src/ralph/supports/models.py index 6963ff4741..61f578cd6e 100644 --- a/src/ralph/supports/models.py +++ b/src/ralph/supports/models.py @@ -12,7 +12,11 @@ from ralph.assets.models.base import BaseObject from ralph.assets.models.choices import ObjectModelType from ralph.lib.mixins.fields import BaseObjectForeignKey -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, PriceMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + PriceMixin +) from ralph.lib.polymorphic.fields import PolymorphicManyToManyField from ralph.lib.polymorphic.models import PolymorphicQuerySet diff --git a/src/ralph/supports/tests/factories.py b/src/ralph/supports/tests/factories.py index 21febceaf7..6163f39359 100644 --- a/src/ralph/supports/tests/factories.py +++ b/src/ralph/supports/tests/factories.py @@ -13,7 +13,7 @@ BaseObjectsSupport, Support, SupportStatus, - SupportType, + SupportType ) date_now = datetime.now().date() diff --git a/src/ralph/tests/admin.py b/src/ralph/tests/admin.py index bdeccefac7..24011e09e3 100644 --- a/src/ralph/tests/admin.py +++ b/src/ralph/tests/admin.py @@ -14,7 +14,7 @@ Foo, Order, PolymorphicTestModel, - TestManufacturer, + TestManufacturer ) diff --git a/src/ralph/tests/models.py b/src/ralph/tests/models.py index ff3aa4898b..40266e3523 100644 --- a/src/ralph/tests/models.py +++ b/src/ralph/tests/models.py @@ -12,7 +12,7 @@ from ralph.lib.transitions.decorators import transition_action from ralph.lib.transitions.exceptions import ( FreezeAsyncTransition, - RescheduleAsyncTransitionActionLater, + RescheduleAsyncTransitionActionLater ) from ralph.lib.transitions.fields import TransitionField from ralph.lib.transitions.models import TransitionWorkflowBase diff --git a/src/ralph/trade_marks/admin.py b/src/ralph/trade_marks/admin.py index 5263a146c9..d0fc3301d9 100644 --- a/src/ralph/trade_marks/admin.py +++ b/src/ralph/trade_marks/admin.py @@ -6,9 +6,9 @@ from ralph.admin.decorators import register from ralph.admin.filters import ( ChoicesListFilter, - DateListFilter, - RelatedAutocompleteFieldListFilter, custom_title_filter, + DateListFilter, + RelatedAutocompleteFieldListFilter ) from ralph.admin.mixins import RalphAdmin, RalphTabularInline from ralph.admin.views.extra import RalphDetailViewAdmin @@ -17,7 +17,7 @@ DesignForm, PatentForm, TradeMarkForm, - UtilityModelForm, + UtilityModelForm ) from ralph.trade_marks.models import ( Design, @@ -35,7 +35,7 @@ TradeMarksLinkedDomains, UtilityModel, UtilityModelAdditionalCountry, - UtilityModelLinkedDomains, + UtilityModelLinkedDomains ) diff --git a/src/ralph/trade_marks/models.py b/src/ralph/trade_marks/models.py index 27cc74d4e0..7f68d5aa44 100644 --- a/src/ralph/trade_marks/models.py +++ b/src/ralph/trade_marks/models.py @@ -7,7 +7,11 @@ from ralph.assets.models import AssetHolder, BaseObject from ralph.attachments.helpers import get_file_path from ralph.domains.models import Domain -from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, NamedMixin, TimeStampMixin +from ralph.lib.mixins.models import ( + AdminAbsoluteUrlMixin, + NamedMixin, + TimeStampMixin +) def verbose_names(**kwargs): diff --git a/src/ralph/trade_marks/tests/factories.py b/src/ralph/trade_marks/tests/factories.py index c670af80a7..df2e572df6 100644 --- a/src/ralph/trade_marks/tests/factories.py +++ b/src/ralph/trade_marks/tests/factories.py @@ -18,7 +18,7 @@ TradeMarkRegistrarInstitution, TradeMarksLinkedDomains, UtilityModel, - UtilityModelLinkedDomains, + UtilityModelLinkedDomains ) date_now = datetime.now().date() diff --git a/src/ralph/urls/dev.py b/src/ralph/urls/dev.py index 19aecacd39..a60c10fd6e 100644 --- a/src/ralph/urls/dev.py +++ b/src/ralph/urls/dev.py @@ -3,8 +3,8 @@ from django.conf.urls import include, url from django.conf.urls.static import static -from ralph.urls import handler404 # noqa from ralph.urls import urlpatterns as base_urlpatterns +from ralph.urls import handler404 # noqa urlpatterns = base_urlpatterns urlpatterns += [ diff --git a/src/ralph/urls/test.py b/src/ralph/urls/test.py index ddafecb76c..5ce1a4160d 100644 --- a/src/ralph/urls/test.py +++ b/src/ralph/urls/test.py @@ -4,9 +4,8 @@ from ralph.api.tests import api as ralph_api from ralph.lib.custom_fields.tests import urls as custom_fields_tests_urls from ralph.lib.permissions.tests import api as lib_api -from ralph.lib.permissions.tests.test_permission_view import ( - urls as perm_view_url, # noqa -) +from ralph.lib.permissions.tests.test_permission_view import \ + urls as perm_view_url # noqa from ralph.urls.base import urlpatterns as base_urlpatterns urlpatterns = base_urlpatterns diff --git a/src/ralph/virtual/admin.py b/src/ralph/virtual/admin.py index 8e0f092228..deff2dfdc4 100644 --- a/src/ralph/virtual/admin.py +++ b/src/ralph/virtual/admin.py @@ -15,7 +15,7 @@ from ralph.assets.views import ComponentsAdminView, RalphDetailViewAdmin from ralph.configuration_management.views import ( SCMCheckInfo, - SCMStatusCheckInChangeListMixin, + SCMStatusCheckInChangeListMixin ) from ralph.data_center.admin import generate_list_filter_with_common_fields from ralph.data_center.models.physical import DataCenterAsset @@ -35,7 +35,7 @@ CloudProject, CloudProvider, VirtualServer, - VirtualServerType, + VirtualServerType ) if settings.ENABLE_DNSAAS_INTEGRATION: diff --git a/src/ralph/virtual/api.py b/src/ralph/virtual/api.py index a85df17da7..8fbf18199d 100644 --- a/src/ralph/virtual/api.py +++ b/src/ralph/virtual/api.py @@ -12,11 +12,11 @@ BaseObjectSerializer, ComponentSerializerMixin, NetworkComponentSerializerMixin, - ServiceEnvironmentSimpleSerializer, + ServiceEnvironmentSimpleSerializer ) from ralph.assets.api.views import ( - BaseObjectViewSetMixin, base_object_descendant_prefetch_related, + BaseObjectViewSetMixin ) from ralph.assets.models import Ethernet from ralph.configuration_management.api import SCMInfoSerializer @@ -33,7 +33,7 @@ CloudProject, CloudProvider, VirtualServer, - VirtualServerType, + VirtualServerType ) diff --git a/src/ralph/virtual/cloudsync.py b/src/ralph/virtual/cloudsync.py index b3863df949..d34fc3c24a 100644 --- a/src/ralph/virtual/cloudsync.py +++ b/src/ralph/virtual/cloudsync.py @@ -4,7 +4,11 @@ import pkg_resources from django.db.models import Q -from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound +from django.http import ( + HttpResponse, + HttpResponseBadRequest, + HttpResponseNotFound +) from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST diff --git a/src/ralph/virtual/management/commands/openstack_sync.py b/src/ralph/virtual/management/commands/openstack_sync.py index 8160c43757..dbbc3a8606 100644 --- a/src/ralph/virtual/management/commands/openstack_sync.py +++ b/src/ralph/virtual/management/commands/openstack_sync.py @@ -2,7 +2,7 @@ import logging from collections import defaultdict from datetime import datetime, timedelta -from enum import Enum, auto +from enum import auto, Enum from functools import lru_cache from django.conf import settings @@ -14,9 +14,14 @@ from ralph.data_center.models.physical import DataCenterAsset from ralph.lib.openstack.client import ( RalphIronicClient, - RalphOpenStackInfrastructureClient, + RalphOpenStackInfrastructureClient +) +from ralph.virtual.models import ( + CloudFlavor, + CloudHost, + CloudProject, + CloudProvider ) -from ralph.virtual.models import CloudFlavor, CloudHost, CloudProject, CloudProvider logger = logging.getLogger(__name__) diff --git a/src/ralph/virtual/models.py b/src/ralph/virtual/models.py index ae4111a6bb..9c371edb5c 100644 --- a/src/ralph/virtual/models.py +++ b/src/ralph/virtual/models.py @@ -17,7 +17,10 @@ from ralph.assets.models.choices import ComponentType from ralph.assets.models.components import Component, ComponentModel, Ethernet from ralph.assets.utils import DNSaaSPublisherMixin -from ralph.data_center.models.physical import DataCenterAsset, NetworkableBaseObject +from ralph.data_center.models.physical import ( + DataCenterAsset, + NetworkableBaseObject +) from ralph.data_center.models.virtual import Cluster from ralph.data_center.publishers import publish_host_update from ralph.lib.mixins.fields import NullableCharField @@ -25,7 +28,7 @@ AdminAbsoluteUrlMixin, NamedMixin, PreviousStateMixin, - TimeStampMixin, + TimeStampMixin ) from ralph.lib.transitions.fields import TransitionField from ralph.networks.models.networks import IPAddress diff --git a/src/ralph/virtual/tests/factories.py b/src/ralph/virtual/tests/factories.py index e828a815fe..b5bbd6563b 100644 --- a/src/ralph/virtual/tests/factories.py +++ b/src/ralph/virtual/tests/factories.py @@ -8,7 +8,7 @@ EthernetWithIPAddressFactory, MemoryFactory, ProcessorFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory ) from ralph.data_center.tests.factories import DataCenterAssetFactory from ralph.security.tests.factories import SecurityScanFactory @@ -19,7 +19,7 @@ CloudProject, CloudProvider, VirtualServer, - VirtualServerType, + VirtualServerType ) diff --git a/src/ralph/virtual/tests/test_admin.py b/src/ralph/virtual/tests/test_admin.py index 6bc9f9b80a..d816a1f3f7 100644 --- a/src/ralph/virtual/tests/test_admin.py +++ b/src/ralph/virtual/tests/test_admin.py @@ -5,7 +5,7 @@ from ralph.assets.tests.factories import BaseObjectFactory from ralph.data_center.tests.factories import ( DataCenterAssetFactory, - ServiceEnvironmentFactory, + ServiceEnvironmentFactory ) from ralph.licences.tests.factories import LicenceFactory from ralph.tests import RalphTestCase diff --git a/src/ralph/virtual/tests/test_api.py b/src/ralph/virtual/tests/test_api.py index e6bf5c115c..cea0a8d064 100644 --- a/src/ralph/virtual/tests/test_api.py +++ b/src/ralph/virtual/tests/test_api.py @@ -9,9 +9,12 @@ from ralph.assets.tests.factories import ( EnvironmentFactory, EthernetFactory, - ServiceFactory, + ServiceFactory +) +from ralph.data_center.tests.factories import ( + ClusterFactory, + DataCenterAssetFactory ) -from ralph.data_center.tests.factories import ClusterFactory, DataCenterAssetFactory from ralph.lib.custom_fields.models import CustomField, CustomFieldTypes from ralph.networks.tests.factories import IPAddressFactory from ralph.virtual.models import ( @@ -21,7 +24,7 @@ CloudProvider, VirtualComponent, VirtualServer, - VirtualServerType, + VirtualServerType ) from ralph.virtual.tests.factories import ( CloudFlavorFactory, @@ -29,7 +32,7 @@ CloudHostFullFactory, CloudProjectFactory, CloudProviderFactory, - VirtualServerFullFactory, + VirtualServerFullFactory ) diff --git a/src/ralph/virtual/tests/test_models.py b/src/ralph/virtual/tests/test_models.py index 6d0e7c4ca7..d73b694fe3 100644 --- a/src/ralph/virtual/tests/test_models.py +++ b/src/ralph/virtual/tests/test_models.py @@ -7,13 +7,16 @@ from ralph.assets.tests.factories import ( EnvironmentFactory, ServiceEnvironmentFactory, - ServiceFactory, + ServiceFactory +) +from ralph.data_center.tests.factories import ( + DataCenterAssetFullFactory, + RackFactory ) -from ralph.data_center.tests.factories import DataCenterAssetFullFactory, RackFactory from ralph.lib.custom_fields.models import ( CustomField, CustomFieldTypes, - CustomFieldValue, + CustomFieldValue ) from ralph.networks.models import IPAddress from ralph.networks.tests.factories import NetworkFactory @@ -25,7 +28,7 @@ CloudHostFactory, CloudProjectFactory, CloudProviderFactory, - VirtualServerFullFactory, + VirtualServerFullFactory ) diff --git a/src/ralph/virtual/tests/test_openstack_sync.py b/src/ralph/virtual/tests/test_openstack_sync.py index e21eccfb09..421809d06f 100644 --- a/src/ralph/virtual/tests/test_openstack_sync.py +++ b/src/ralph/virtual/tests/test_openstack_sync.py @@ -18,19 +18,19 @@ CloudHost, CloudProject, CloudProvider, - VirtualComponent, + VirtualComponent ) from ralph.virtual.tests.factories import ( CloudFlavorFactory, CloudHostFactory, CloudHostFullFactory, CloudProjectFactory, - CloudProviderFactory, + CloudProviderFactory ) from ralph.virtual.tests.samples.openstack_data import ( OPENSTACK_DATA, OPENSTACK_FLAVORS, - OPENSTACK_INSTANCES, + OPENSTACK_INSTANCES ) From f1b5cc39e5bed7c269a41fd602e51951908812c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Szulc?= Date: Tue, 10 Dec 2024 11:28:41 +0100 Subject: [PATCH 11/11] Bump pyflakes --- requirements/code_style.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/code_style.txt b/requirements/code_style.txt index a261921910..4e603cdb68 100644 --- a/requirements/code_style.txt +++ b/requirements/code_style.txt @@ -1,3 +1,3 @@ flake8==3.7.9 isort==4.2.5 -pyflakes==1.5.0 +pyflakes==2.1.0