Skip to content

Commit 8113670

Browse files
committed
Merge branch 'ng' of github.com:allegro/ralph into django-2.1
2 parents b0b5863 + 4565808 commit 8113670

File tree

23 files changed

+179
-53
lines changed

23 files changed

+179
-53
lines changed

debian/changelog

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,50 @@
1+
ralph (20241104.2) bionic; urgency=medium
2+
3+
[ awieckowski ]
4+
* Increase max user department field length
5+
* Add missing migration
6+
7+
[ Paweł Szulc ]
8+
* Fix ldap sync when bytes received
9+
10+
-- Paweł Szulc <[email protected]> Mon, 04 Nov 2024 13:06:26 +0000
11+
12+
ralph (20241104.1) bionic; urgency=medium
13+
14+
* Fix method to get limit choices
15+
* Fix data center asset export not getting filter from request
16+
* Fix format to work with newer flake
17+
* Fix prefetches
18+
* Make prefetches work for filtered and not filtered export
19+
* loosen queries count constraint for export
20+
21+
-- Paweł Szulc <[email protected]> Mon, 04 Nov 2024 10:17:53 +0000
22+
23+
ralph (20241029.1) bionic; urgency=medium
24+
25+
[ awieckowski ]
26+
* Fix LDAP Groups sync
27+
28+
[ Paweł Szulc ]
29+
* Fix bulk edit for some models
30+
31+
-- Paweł Szulc <[email protected]> Tue, 29 Oct 2024 13:00:03 +0000
32+
33+
ralph (20241028.1) bionic; urgency=medium
34+
35+
* Fix virtual server - hypervisor
36+
* Revert remove barcode from factory
37+
* Fix virtual server - service env optional
38+
39+
-- Paweł Szulc <[email protected]> Mon, 28 Oct 2024 15:23:53 +0000
40+
41+
ralph (20241023.1) bionic; urgency=medium
42+
43+
* Updated changelog for 20241011.1 version.
44+
* Fix data not JSON-serializable
45+
46+
-- Paweł Szulc <[email protected]> Wed, 23 Oct 2024 10:29:45 +0000
47+
148
ralph (20241011.1) bionic; urgency=medium
249

350
[ Paweł Szulc ]

requirements/prod_ldap.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
-r prod.txt
2-
django-auth-ldap==1.2.7
2+
django-auth-ldap==1.6.1

src/ralph/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def monkey_options_init(self, meta, app_label):
77
self._old__init__(meta, app_label)
88
self.default_permissions = ('add', 'change', 'delete', 'view')
99

10-
# TODO: create PR to Django - default_permissions from settings
10+
1111
Options._old__init__ = Options.__init__
1212
Options.__init__ = lambda self, meta, app_label=None: monkey_options_init(
1313
self, meta, app_label

src/ralph/accounts/helpers.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@
1010
from ralph.lib.transitions.models import Transition
1111
from ralph.sim_cards.models import SIMCard
1212

13-
ACCEPTANCE_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_ID'] # noqa: E509
14-
ACCEPTANCE_SIM_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_SIM_ID'] # noqa: E509
15-
ACCEPTANCE_BACK_OFFICE_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_STATUS'] # noqa: E509
16-
ACCEPTANCE_SIMCARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['SIMCARD_ACCEPT_STATUS'] # noqa: E509
17-
ACCEPTANCE_LOAN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['LOAN_TRANSITION_ID'] # noqa: E509
18-
ACCEPTANCE_BACK_OFFICE_ACCEPT_LOAN_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_LOAN_STATUS'] # noqa: E509
19-
ACCEPTANCE_RETURN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['RETURN_TRANSITION_ID'] # noqa: E509
20-
ACCEPTANCE_BACK_OFFICE_RETURN_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_RETURN_STATUS'] # noqa: E509
21-
ACCEPTANCE_ACCESS_CARD_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_ACCESS_CARD_ID'] # noqa: E509
22-
ACCEPTANCE_ACCESS_CARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['ACCESS_CARD_ACCEPT_ACCEPT_STATUS'] # noqa: E509
23-
ACCEPTANCE_BACK_OFFICE_TEAM_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_TEAM_ACCEPT_STATUS'] # noqa: E509
24-
ACCEPTANCE_TEAM_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_TEAM_ACCEPT_ID'] # noqa: E509
25-
ACCEPTANCE_BACK_OFFICE_TEST_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_TEST_ACCEPT_STATUS'] # noqa: E509
26-
ACCEPTANCE_TEST_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_TEST_ACCEPT_ID'] # noqa: E509
13+
ACCEPTANCE_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_ID'] # noqa
14+
ACCEPTANCE_SIM_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_SIM_ID'] # noqa
15+
ACCEPTANCE_BACK_OFFICE_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_STATUS'] # noqa
16+
ACCEPTANCE_SIMCARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['SIMCARD_ACCEPT_STATUS'] # noqa
17+
ACCEPTANCE_LOAN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['LOAN_TRANSITION_ID'] # noqa
18+
ACCEPTANCE_BACK_OFFICE_ACCEPT_LOAN_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_LOAN_STATUS'] # noqa
19+
ACCEPTANCE_RETURN_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['RETURN_TRANSITION_ID'] # noqa
20+
ACCEPTANCE_BACK_OFFICE_RETURN_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_ACCEPT_RETURN_STATUS'] # noqa
21+
ACCEPTANCE_ACCESS_CARD_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_ACCESS_CARD_ID'] # noqa
22+
ACCEPTANCE_ACCESS_CARD_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['ACCESS_CARD_ACCEPT_ACCEPT_STATUS'] # noqa
23+
ACCEPTANCE_BACK_OFFICE_TEAM_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_TEAM_ACCEPT_STATUS'] # noqa
24+
ACCEPTANCE_TEAM_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_TEAM_ACCEPT_ID'] # noqa
25+
ACCEPTANCE_BACK_OFFICE_TEST_ACCEPT_STATUS = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['BACK_OFFICE_TEST_ACCEPT_STATUS'] # noqa
26+
ACCEPTANCE_TEST_ACCEPT_TRANSITION_ID = settings.ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG['TRANSITION_TEST_ACCEPT_ID'] # noqa
2727

2828

2929
def transition_exists(transition_id):

src/ralph/accounts/ldap.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ def mirror_groups(self):
6666
new_groups = [Group.objects.get_or_create(name=name)[0] for name
6767
in target_group_names if name not in existing_group_names]
6868

69-
self._user.groups = existing_groups + new_groups
69+
self._user.groups.set(existing_groups + new_groups)
70+
7071

7172
_LDAPUser._mirror_groups_original = _LDAPUser._mirror_groups
7273
_LDAPUser._mirror_groups = mirror_groups

src/ralph/accounts/management/commands/ldap_sync.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@
2424
ldap_module_exists = False
2525

2626

27+
def decode_nested_dict(data):
28+
if isinstance(data, dict):
29+
return {key: decode_nested_dict(value) for key, value in data.items()}
30+
elif isinstance(data, list):
31+
return [decode_nested_dict(element) for element in data]
32+
elif isinstance(data, bytes):
33+
try:
34+
return data.decode('utf-8')
35+
except UnicodeDecodeError:
36+
return data
37+
else:
38+
return data
39+
40+
2741
def _truncate(field_key, field_name, ldap_dict):
2842
"""
2943
Truncate user's field when it's longer then default django value, which is
@@ -274,16 +288,8 @@ def populate_users(self):
274288
"""Load users from ldap and populate them. Returns number of users."""
275289
synced = 0
276290
for user_dn, ldap_dict in self._get_users():
277-
if ldap_dict.get('c'):
278-
try:
279-
ldap_dict['c'] = [v.decode('utf-8') for v in ldap_dict['c']]
280-
except UnicodeDecodeError:
281-
logger.error(
282-
"Can't decode country %s for user %s",
283-
ldap_dict['c'],
284-
user_dn
285-
)
286-
continue
291+
# decode bytes to str
292+
ldap_dict = decode_nested_dict(ldap_dict)
287293
_truncate('sn', 'last_name', ldap_dict)
288294
user = self._create_or_update_user(user_dn, ldap_dict)
289295
self.nested_groups.handle(user)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 2.0.13 on 2024-10-30 12:35
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('accounts', '0009_auto_20240621_1217'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='ralphuser',
15+
name='department',
16+
field=models.CharField(blank=True, max_length=128, verbose_name='department'),
17+
),
18+
]

src/ralph/accounts/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class RalphUser(
102102
)
103103
department = models.CharField(
104104
verbose_name=_('department'),
105-
max_length=64,
105+
max_length=128,
106106
blank=True,
107107
)
108108
manager = models.CharField(

src/ralph/admin/mixins.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,9 +421,6 @@ def get_export_queryset(self, request):
421421
)
422422
if resource_prefetch_related:
423423
queryset = queryset.prefetch_related(*resource_prefetch_related)
424-
# cast to list to consider all prefetch_related (django-import-export
425-
# use queryset.iterator() to "save memory", but then for every row
426-
# sql queries are made to fetch all m2m relations)
427424
return list(queryset)
428425

429426
def get_export_resource_class(self):
@@ -541,8 +538,9 @@ def get_queryset(self, request):
541538
qs = super().get_queryset(request)
542539
id_list = request.GET.getlist(BULK_EDIT_VAR_IDS, [])
543540
if id_list:
544-
qs = qs.filter(pk__in=id_list)
545-
return qs
541+
return self.model.objects.filter(id__in=id_list)
542+
else:
543+
return qs
546544

547545
def get_list_display(self, request):
548546
"""

src/ralph/api/routers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,5 @@ def get(self, request, *args, **kwargs):
5858

5959
return APIRoot.as_view()
6060

61+
6162
router = RalphRouter()

src/ralph/assets/api/serializers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ def get_object_type(self, instance):
5353

5454
class OwnersFromServiceEnvSerializerMixin(RalphAPISerializer):
5555
business_owners = SimpleRalphUserSerializer(
56-
many=True, source='service_env.service.business_owners')
56+
many=True, source='service_env.service.business_owners', required=False)
5757
technical_owners = SimpleRalphUserSerializer(
58-
many=True, source='service_env.service.technical_owners')
58+
many=True, source='service_env.service.technical_owners', required=False)
5959

6060

6161
class BusinessSegmentSerializer(RalphAPISerializer):
@@ -317,6 +317,7 @@ class Meta:
317317
'parent'
318318
)
319319

320+
320321
# TODO: Is there a better way to make it work since drf 3.5?
321322
del ConfigurationClassSimpleSerializer._declared_fields['tags']
322323

src/ralph/assets/invoice_report.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22
import datetime
3+
import json
34
import logging
45

56
from django.contrib import messages
@@ -116,7 +117,7 @@ def _get_report_data(self, request, queryset):
116117
'model': queryset.model._meta.model_name,
117118
'base_info': {
118119
'invoice_no': first_item.invoice_no,
119-
'invoice_date': first_item.invoice_date,
120+
'invoice_date': str(first_item.invoice_date),
120121
'provider': first_item.provider,
121122
'datetime': datetime.datetime.now().strftime(
122123
self._invoice_report_datetime_format
@@ -148,6 +149,9 @@ def _get_pdf_content(self, data):
148149
template_content = f.read()
149150

150151
service_pdf = ExternalService('PDF')
152+
# Make sure data is JSON-serializable
153+
# Will throw otherwise
154+
data = json.loads(json.dumps(data))
151155
result = service_pdf.run(
152156
template=template_content,
153157
data=data,

src/ralph/data_center/admin.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@
2828
from ralph.admin.mixins import (
2929
BulkEditChangeListMixin,
3030
RalphAdmin,
31+
RalphAdminImportExportMixin,
3132
RalphTabularInline
3233
)
3334
from ralph.admin.views.extra import RalphDetailViewAdmin
3435
from ralph.admin.views.main import RalphChangeList
3536
from ralph.admin.views.multiadd import MulitiAddAdminMixin
3637
from ralph.assets.invoice_report import AssetInvoiceReportMixin
37-
from ralph.assets.models.base import BaseObject
38+
from ralph.assets.models.base import BaseObject, BaseObjectPolymorphicQuerySet
3839
from ralph.assets.models.components import Ethernet
3940
from ralph.assets.views import ComponentsAdminView
4041
from ralph.attachments.admin import AttachmentsMixin
@@ -491,11 +492,25 @@ class DataCenterAssetAdmin(
491492
)
492493

493494
def get_export_queryset(self, request):
494-
return DataCenterAsset.polymorphic_objects.select_related(
495-
*self.list_select_related
496-
).polymorphic_prefetch_related(
497-
DataCenterAsset=['tags', 'ethernet_set__ipaddress', 'parent__ethernet_set__ipaddress'],
495+
qs = (
496+
super(RalphAdminImportExportMixin, self)
497+
.get_export_queryset(request)
498+
.select_related(
499+
*self.list_select_related
500+
)
498501
)
502+
if isinstance(qs, BaseObjectPolymorphicQuerySet):
503+
return qs.polymorphic_prefetch_related(
504+
DataCenterAsset=[
505+
'tags',
506+
'ethernet_set__ipaddress',
507+
'parent__ethernet_set__ipaddress'
508+
]
509+
)
510+
else:
511+
return qs.prefetch_related(
512+
'tags', 'ethernet_set__ipaddress', 'parent__ethernet_set__ipaddress'
513+
)
499514

500515
def get_multiadd_fields(self, obj=None):
501516
multiadd_fields = [

src/ralph/data_importer/resources.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,16 @@ class DataCenterAssetResource(ResourceWithPrice, RalphModelResource):
306306
class Meta:
307307
model = physical.DataCenterAsset
308308
select_related = (
309+
'model__manufacturer', 'model__category',
309310
'service_env__service', 'service_env__environment',
310311
'rack__server_room__data_center',
312+
'configuration_path',
313+
'property_of',
314+
'parent',
315+
'budget_info',
316+
)
317+
prefetch_related = (
318+
'tags', 'ethernet_set__ipaddress', 'parent__ethernet_set__ipaddress',
311319
)
312320
exclude = ('content_type', 'asset_ptr', 'baseobject_ptr', 'connections')
313321

src/ralph/data_importer/tests/test_export.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ def test_data_center_asset_export_queries_count(self):
114114
DataCenterAsset
115115
), max_queries=12)
116116

117+
def test_data_center_asset_export_filtered(self):
118+
self._init(10)
119+
first_id = next(iter(self.data_center_assets_map.keys()))
120+
with CaptureQueriesContext(connections['default']) as cqc:
121+
export_data = self._export(
122+
DataCenterAsset, filters={'id': first_id}
123+
)
124+
queries = len(cqc)
125+
self.assertEqual(len(export_data.dict), 1)
126+
self.assertLessEqual(queries, 12)
117127

118128
class DataCenterAssetExporterTestCaseWithParent(DataCenterAssetExporterTestCase):
119129
def _init(self, num=10):

src/ralph/helpers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def generate_pdf_response(pdf_data, file_name):
4141
)
4242
return response
4343

44+
4445
CACHE_DEFAULT = object()
4546

4647

src/ralph/lib/metrics/collector.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def build_statsd_client(
2525
ipv6=ipv6
2626
)
2727

28+
2829
if settings.COLLECT_METRICS and statsd is None:
2930
statsd = build_statsd_client()
3031

src/ralph/lib/mixins/fields.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ def deconstruct(self):
232232
def limit_choices_to(self):
233233
return self.limit_choices()
234234

235+
def get_limit_choices_to(self):
236+
return self.limit_choices()
237+
235238
def limit_choices(self):
236239
"""
237240
Add limit_choices_to search by content_type for models

src/ralph/licences/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def get_queryset(self):
111111
}
112112
)
113113

114+
114115
LICENCES_RELATED_OBJECTS_PREFETCH_RELATED = [
115116
'users',
116117
# prefetch all baseobjects related with licence; this allows to call

src/ralph/networks/filters.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ def get_private_network_filter():
2424
max_ip = int(network.broadcast_address)
2525
filter_ |= Q(min_ip__gte=min_ip, max_ip__lte=max_ip)
2626
return filter_
27+
28+
2729
PRIVATE_NETWORK_FILTER = get_private_network_filter()
2830

2931

0 commit comments

Comments
 (0)