From 66a769edcadfe6d41ef551d56f81770eed7cc964 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Nov 2024 21:25:39 +0100 Subject: [PATCH 01/19] [PUI] SSO improvments (#8527) * disable PUI SSO login button if not fully set up see https://github.com/inventree/InvenTree/issues/7972 * refactor provider urls to also support oidc providers * cleanup --- .../InvenTree/InvenTree/social_auth_urls.py | 97 ++++++++----- src/backend/InvenTree/InvenTree/urls.py | 132 +++++++++--------- .../src/components/buttons/SSOButton.tsx | 26 ++-- 3 files changed, 145 insertions(+), 110 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/social_auth_urls.py b/src/backend/InvenTree/InvenTree/social_auth_urls.py index 4be0b8d09f..a7ad13dd6f 100644 --- a/src/backend/InvenTree/InvenTree/social_auth_urls.py +++ b/src/backend/InvenTree/InvenTree/social_auth_urls.py @@ -6,6 +6,7 @@ from importlib import import_module from django.conf import settings from django.urls import NoReverseMatch, include, path, reverse +import allauth.socialaccount.providers.openid_connect.views as oidc_views from allauth.account.models import EmailAddress from allauth.socialaccount import providers from allauth.socialaccount.providers.oauth2.views import OAuth2Adapter, OAuth2LoginView @@ -44,7 +45,7 @@ class GenericOAuth2ApiConnectView(GenericOAuth2ApiLoginView): return super().dispatch(request, *args, **kwargs) -def handle_oauth2(adapter: OAuth2Adapter): +def handle_oauth2(adapter: OAuth2Adapter, provider=None): """Define urls for oauth2 endpoints.""" return [ path( @@ -60,6 +61,22 @@ def handle_oauth2(adapter: OAuth2Adapter): ] +def handle_oidc(provider): + """Define urls for oidc endpoints.""" + return [ + path( + 'login/', + lambda x: oidc_views.login(x, provider.id), + name=f'{provider.id}_api_login', + ), + path( + 'connect/', + lambda x: oidc_views.callback(x, provider.id), + name=f'{provider.id}_api_connect', + ), + ] + + legacy = { 'twitter': 'twitter_oauth2', 'bitbucket': 'bitbucket_oauth2', @@ -70,47 +87,53 @@ legacy = { # Collect urls for all loaded providers -social_auth_urlpatterns = [] +def get_provider_urls() -> list: + """Collect urls for all loaded providers. -provider_urlpatterns = [] + Returns: + list: List of urls for all loaded providers. + """ + auth_provider_routes = [] -for name, provider in providers.registry.provider_map.items(): - try: - prov_mod = import_module(provider.get_package() + '.views') - except ImportError: - logger.exception('Could not import authentication provider %s', name) - continue + for name, provider in providers.registry.provider_map.items(): + try: + prov_mod = import_module(provider.get_package() + '.views') + except ImportError: + logger.exception('Could not import authentication provider %s', name) + continue - # Try to extract the adapter class - adapters = [ - cls - for cls in prov_mod.__dict__.values() - if isinstance(cls, type) - and cls != OAuth2Adapter - and issubclass(cls, OAuth2Adapter) - ] + # Try to extract the adapter class + adapters = [ + cls + for cls in prov_mod.__dict__.values() + if isinstance(cls, type) + and cls != OAuth2Adapter + and issubclass(cls, OAuth2Adapter) + ] - # Get urls - urls = [] - if len(adapters) == 1: - urls = handle_oauth2(adapter=adapters[0]) - elif provider.id in legacy: - logger.warning( - '`%s` is not supported on platform UI. Use `%s` instead.', - provider.id, - legacy[provider.id], - ) - continue - else: - logger.error( - 'Found handler that is not yet ready for platform UI: `%s`. Open an feature request on GitHub if you need it implemented.', - provider.id, - ) - continue - provider_urlpatterns += [path(f'{provider.id}/', include(urls))] + # Get urls + urls = [] + if len(adapters) == 1: + if provider.id == 'openid_connect': + urls = handle_oidc(provider) + else: + urls = handle_oauth2(adapter=adapters[0], provider=provider) + elif provider.id in legacy: + logger.warning( + '`%s` is not supported on platform UI. Use `%s` instead.', + provider.id, + legacy[provider.id], + ) + continue + else: + logger.error( + 'Found handler that is not yet ready for platform UI: `%s`. Open an feature request on GitHub if you need it implemented.', + provider.id, + ) + continue + auth_provider_routes += [path(f'{provider.id}/', include(urls))] - -social_auth_urlpatterns += provider_urlpatterns + return auth_provider_routes class SocialProviderListResponseSerializer(serializers.Serializer): diff --git a/src/backend/InvenTree/InvenTree/urls.py b/src/backend/InvenTree/InvenTree/urls.py index ef5e4d8eb5..43c16a14bf 100644 --- a/src/backend/InvenTree/InvenTree/urls.py +++ b/src/backend/InvenTree/InvenTree/urls.py @@ -54,7 +54,7 @@ from .social_auth_urls import ( EmailRemoveView, EmailVerifyView, SocialProviderListView, - social_auth_urlpatterns, + get_provider_urls, ) from .views import ( AboutView, @@ -78,6 +78,71 @@ from .views import ( admin.site.site_header = 'InvenTree Admin' +settings_urls = [ + path('i18n/', include('django.conf.urls.i18n')), + path('appearance/', AppearanceSelectView.as_view(), name='settings-appearance'), + # Catch any other urls + path( + '', + SettingsView.as_view(template_name='InvenTree/settings/settings.html'), + name='settings', + ), +] + +notifications_urls = [ + # Catch any other urls + path('', NotificationsView.as_view(), name='notifications') +] + +classic_frontendpatterns = [ + # Apps + # + path('build/', include(build_urls)), + path('common/', include(common_urls)), + path('company/', include(company_urls)), + path('order/', include(order_urls)), + path('manufacturer-part/', include(manufacturer_part_urls)), + path('part/', include(part_urls)), + path('stock/', include(stock_urls)), + path('supplier-part/', include(supplier_part_urls)), + path('edit-user/', EditUserView.as_view(), name='edit-user'), + path('set-password/', SetPasswordView.as_view(), name='set-password'), + path('index/', IndexView.as_view(), name='index'), + path('notifications/', include(notifications_urls)), + path('search/', SearchView.as_view(), name='search'), + path('settings/', include(settings_urls)), + path('about/', AboutView.as_view(), name='about'), + path('stats/', DatabaseStatsView.as_view(), name='stats'), + # DB user sessions + path( + 'accounts/sessions/other/delete/', + view=CustomSessionDeleteOtherView.as_view(), + name='session_delete_other', + ), + re_path( + r'^accounts/sessions/(?P\w+)/delete/$', + view=CustomSessionDeleteView.as_view(), + name='session_delete', + ), + # Single Sign On / allauth + # overrides of urlpatterns + path('accounts/email/', CustomEmailView.as_view(), name='account_email'), + path( + 'accounts/social/connections/', + CustomConnectionsView.as_view(), + name='socialaccount_connections', + ), + re_path( + r'^accounts/password/reset/key/(?P[0-9A-Za-z]+)-(?P.+)/$', + CustomPasswordResetFromKeyView.as_view(), + name='account_reset_password_from_key', + ), + # Override login page + path('accounts/login/', CustomLoginView.as_view(), name='account_login'), + path('accounts/', include('allauth_2fa.urls')), # MFA support + path('accounts/', include('allauth.urls')), # included urlpatterns +] + apipatterns = [ # Global search @@ -167,7 +232,7 @@ apipatterns = [ path('', EmailListView.as_view(), name='email-list'), ]), ), - path('social/', include(social_auth_urlpatterns)), + path('social/', include(get_provider_urls())), path( 'social/', SocialAccountListView.as_view(), name='social_account_list' ), @@ -197,21 +262,6 @@ apipatterns = [ re_path(r'^.*$', NotFoundView.as_view(), name='api-404'), ] -settings_urls = [ - path('i18n/', include('django.conf.urls.i18n')), - path('appearance/', AppearanceSelectView.as_view(), name='settings-appearance'), - # Catch any other urls - path( - '', - SettingsView.as_view(template_name='InvenTree/settings/settings.html'), - name='settings', - ), -] - -notifications_urls = [ - # Catch any other urls - path('', NotificationsView.as_view(), name='notifications') -] # These javascript files are served "dynamically" - i.e. rendered on demand dynamic_javascript_urls = [ @@ -400,54 +450,6 @@ if settings.ENABLE_CLASSIC_FRONTEND: re_path(r'^js/i18n/', include(translated_javascript_urls)), ] -classic_frontendpatterns = [ - # Apps - # - path('build/', include(build_urls)), - path('common/', include(common_urls)), - path('company/', include(company_urls)), - path('order/', include(order_urls)), - path('manufacturer-part/', include(manufacturer_part_urls)), - path('part/', include(part_urls)), - path('stock/', include(stock_urls)), - path('supplier-part/', include(supplier_part_urls)), - path('edit-user/', EditUserView.as_view(), name='edit-user'), - path('set-password/', SetPasswordView.as_view(), name='set-password'), - path('index/', IndexView.as_view(), name='index'), - path('notifications/', include(notifications_urls)), - path('search/', SearchView.as_view(), name='search'), - path('settings/', include(settings_urls)), - path('about/', AboutView.as_view(), name='about'), - path('stats/', DatabaseStatsView.as_view(), name='stats'), - # DB user sessions - path( - 'accounts/sessions/other/delete/', - view=CustomSessionDeleteOtherView.as_view(), - name='session_delete_other', - ), - re_path( - r'^accounts/sessions/(?P\w+)/delete/$', - view=CustomSessionDeleteView.as_view(), - name='session_delete', - ), - # Single Sign On / allauth - # overrides of urlpatterns - path('accounts/email/', CustomEmailView.as_view(), name='account_email'), - path( - 'accounts/social/connections/', - CustomConnectionsView.as_view(), - name='socialaccount_connections', - ), - re_path( - r'^accounts/password/reset/key/(?P[0-9A-Za-z]+)-(?P.+)/$', - CustomPasswordResetFromKeyView.as_view(), - name='account_reset_password_from_key', - ), - # Override login page - path('accounts/login/', CustomLoginView.as_view(), name='account_login'), - path('accounts/', include('allauth_2fa.urls')), # MFA support - path('accounts/', include('allauth.urls')), # included urlpatterns -] urlpatterns = [] diff --git a/src/frontend/src/components/buttons/SSOButton.tsx b/src/frontend/src/components/buttons/SSOButton.tsx index e16548a331..4454c200e8 100644 --- a/src/frontend/src/components/buttons/SSOButton.tsx +++ b/src/frontend/src/components/buttons/SSOButton.tsx @@ -1,4 +1,4 @@ -import { Button } from '@mantine/core'; +import { Button, Tooltip } from '@mantine/core'; import { IconBrandAzure, IconBrandBitbucket, @@ -14,6 +14,7 @@ import { IconLogin } from '@tabler/icons-react'; +import { t } from '@lingui/macro'; import { api } from '../../App'; import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { apiUrl } from '../../states/ApiState'; @@ -49,14 +50,23 @@ export function SsoButton({ provider }: Readonly<{ provider: Provider }>) { } return ( - + + ); } function getBrandIcon(provider: Provider) { From 5e762bc7f7c873c53240ededb8f7dba13795dab1 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 25 Nov 2024 02:40:55 +0100 Subject: [PATCH 02/19] Change picture for external stock location (#8543) * New pic * Marked external icon in picture --- .../images/stock/stock_external_icon.png | Bin 54395 -> 66122 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/docs/assets/images/stock/stock_external_icon.png b/docs/docs/assets/images/stock/stock_external_icon.png index 8aeda5233d7cf9169d5f58d5cf901f28efebb3a5..26704e84b012f5403af82c195e3be10952e99a5e 100644 GIT binary patch literal 66122 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 literal 54395 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

x>8Yyg0KTMqXh&@g`@dcRt#y9Vv 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 Date: Mon, 25 Nov 2024 21:36:31 +1100 Subject: [PATCH 03/19] API date filter updates (#8544) * Add 'stocktake_before' and 'stocktake_after' filters for StockItem API * Enable new filters for StockItemTable * Update CUI table filters * Add more date filter options for orders * Add date filters to BuildList * Update BuildOrderTable filters * Add more order date filters * Cleanup PurchaseOrderFilter code * Implement more PUI table filters * Add "Completion Date" column to PurchaseOrderTable * Update ReturnOrderTable * Add 'text' option for TableFilter * filter state management * Bump API version * Sorting for table filters * Add playwright tests for stock table filtering * Playwright updates - Add some helper functions for common operations * Refactoring for Playwright tests --- .../InvenTree/InvenTree/api_version.py | 9 +- src/backend/InvenTree/build/api.py | 32 ++++- src/backend/InvenTree/order/api.py | 101 +++++++++++----- src/backend/InvenTree/part/api.py | 4 +- src/backend/InvenTree/stock/api.py | 21 +++- .../templates/js/translated/table_filters.js | 4 +- .../src/pages/stock/LocationDetail.tsx | 8 -- src/frontend/src/tables/ColumnRenderers.tsx | 8 ++ src/frontend/src/tables/Filter.tsx | 57 ++++++++- .../src/tables/FilterSelectDrawer.tsx | 114 +++++++++++++----- .../src/tables/build/BuildOrderTable.tsx | 14 ++- .../tables/purchasing/PurchaseOrderTable.tsx | 18 ++- .../src/tables/sales/ReturnOrderTable.tsx | 21 +++- .../src/tables/sales/SalesOrderTable.tsx | 14 ++- .../src/tables/stock/StockItemTable.tsx | 107 ++++++++++++++-- src/frontend/tests/helpers.ts | 46 +++++++ src/frontend/tests/pages/pui_build.spec.ts | 30 +++-- .../tests/pages/pui_dashboard.spec.ts | 4 +- src/frontend/tests/pages/pui_part.spec.ts | 9 +- .../tests/pages/pui_purchase_order.spec.ts | 25 ++++ src/frontend/tests/pages/pui_stock.spec.ts | 42 ++++++- src/frontend/tests/pui_tables.spec.ts | 22 ++-- 22 files changed, 586 insertions(+), 124 deletions(-) create mode 100644 src/frontend/tests/helpers.ts diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 76907a626a..df82fc361e 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,13 +1,20 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 283 +INVENTREE_API_VERSION = 284 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v284 - 2024-11-25 : https://github.com/inventree/InvenTree/pull/8544 + - Adds new date filters to the StockItem API + - Adds new date filters to the BuildOrder API + - Adds new date filters to the SalesOrder API + - Adds new date filters to the PurchaseOrder API + - Adds new date filters to the ReturnOrder API + v283 - 2024-11-20 : https://github.com/inventree/InvenTree/pull/8524 - Adds "note" field to the PartRelated API endpoint diff --git a/src/backend/InvenTree/build/api.py b/src/backend/InvenTree/build/api.py index 096a42683e..0eeb17ed61 100644 --- a/src/backend/InvenTree/build/api.py +++ b/src/backend/InvenTree/build/api.py @@ -23,7 +23,7 @@ import build.serializers from build.models import Build, BuildLine, BuildItem import part.models from users.models import Owner -from InvenTree.filters import SEARCH_ORDER_FILTER_ALIAS +from InvenTree.filters import InvenTreeDateFilter, SEARCH_ORDER_FILTER_ALIAS class BuildFilter(rest_filters.FilterSet): @@ -179,6 +179,36 @@ class BuildFilter(rest_filters.FilterSet): return queryset.exclude(project_code=None) return queryset.filter(project_code=None) + created_before = InvenTreeDateFilter( + label=_('Created before'), + field_name='creation_date', lookup_expr='lt'\ + ) + + created_after = InvenTreeDateFilter( + label=_('Created after'), + field_name='creation_date', lookup_expr='gt' + ) + + target_date_before = InvenTreeDateFilter( + label=_('Target date before'), + field_name='target_date', lookup_expr='lt' + ) + + target_date_after = InvenTreeDateFilter( + label=_('Target date after'), + field_name='target_date', lookup_expr='gt' + ) + + completed_before = InvenTreeDateFilter( + label=_('Completed before'), + field_name='completion_date', lookup_expr='lt' + ) + + completed_after = InvenTreeDateFilter( + label=_('Completed after'), + field_name='completion_date', lookup_expr='gt' + ) + class BuildMixin: """Mixin class for Build API endpoints.""" diff --git a/src/backend/InvenTree/order/api.py b/src/backend/InvenTree/order/api.py index b5671c5952..dbbe60c0b8 100644 --- a/src/backend/InvenTree/order/api.py +++ b/src/backend/InvenTree/order/api.py @@ -21,7 +21,11 @@ import company.models from generic.states.api import StatusView from importer.mixins import DataExportViewMixin from InvenTree.api import ListCreateDestroyAPIView, MetadataView -from InvenTree.filters import SEARCH_ORDER_FILTER, SEARCH_ORDER_FILTER_ALIAS +from InvenTree.filters import ( + SEARCH_ORDER_FILTER, + SEARCH_ORDER_FILTER_ALIAS, + InvenTreeDateFilter, +) from InvenTree.helpers import str2bool from InvenTree.helpers_model import construct_absolute_url, get_base_url from InvenTree.mixins import CreateAPI, ListAPI, ListCreateAPI, RetrieveUpdateDestroyAPI @@ -140,6 +144,22 @@ class OrderFilter(rest_filters.FilterSet): queryset=Owner.objects.all(), field_name='responsible', label=_('Responsible') ) + created_before = InvenTreeDateFilter( + label=_('Created Before'), field_name='creation_date', lookup_expr='lt' + ) + + created_after = InvenTreeDateFilter( + label=_('Created After'), field_name='creation_date', lookup_expr='gt' + ) + + target_date_before = InvenTreeDateFilter( + label=_('Target Date Before'), field_name='target_date', lookup_expr='lt' + ) + + target_date_after = InvenTreeDateFilter( + label=_('Target Date After'), field_name='target_date', lookup_expr='gt' + ) + class LineItemFilter(rest_filters.FilterSet): """Base class for custom API filters for order line item list(s).""" @@ -171,6 +191,41 @@ class PurchaseOrderFilter(OrderFilter): model = models.PurchaseOrder fields = ['supplier'] + part = rest_filters.ModelChoiceFilter( + queryset=Part.objects.all(), + field_name='part', + label=_('Part'), + method='filter_part', + ) + + def filter_part(self, queryset, name, part: Part): + """Filter by provided Part instance.""" + orders = part.purchase_orders() + + return queryset.filter(pk__in=[o.pk for o in orders]) + + supplier_part = rest_filters.ModelChoiceFilter( + queryset=company.models.SupplierPart.objects.all(), + label=_('Supplier Part'), + method='filter_supplier_part', + ) + + def filter_supplier_part( + self, queryset, name, supplier_part: company.models.SupplierPart + ): + """Filter by provided SupplierPart instance.""" + orders = supplier_part.purchase_orders() + + return queryset.filter(pk__in=[o.pk for o in orders]) + + completed_before = InvenTreeDateFilter( + label=_('Completed Before'), field_name='complete_date', lookup_expr='lt' + ) + + completed_after = InvenTreeDateFilter( + label=_('Completed After'), field_name='complete_date', lookup_expr='gt' + ) + class PurchaseOrderMixin: """Mixin class for PurchaseOrder endpoints.""" @@ -221,32 +276,6 @@ class PurchaseOrderList(PurchaseOrderMixin, DataExportViewMixin, ListCreateAPI): params = self.request.query_params - # Attempt to filter by part - part = params.get('part', None) - - if part is not None: - try: - part = Part.objects.get(pk=part) - queryset = queryset.filter( - id__in=[p.id for p in part.purchase_orders()] - ) - except (Part.DoesNotExist, ValueError): - pass - - # Attempt to filter by supplier part - supplier_part = params.get('supplier_part', None) - - if supplier_part is not None: - try: - supplier_part = company.models.SupplierPart.objects.get( - pk=supplier_part - ) - queryset = queryset.filter( - id__in=[p.id for p in supplier_part.purchase_orders()] - ) - except (ValueError, company.models.SupplierPart.DoesNotExist): - pass - # Filter by 'date range' min_date = params.get('min_date', None) max_date = params.get('max_date', None) @@ -276,6 +305,7 @@ class PurchaseOrderList(PurchaseOrderMixin, DataExportViewMixin, ListCreateAPI): 'reference', 'supplier__name', 'target_date', + 'complete_date', 'line_items', 'status', 'responsible', @@ -648,6 +678,14 @@ class SalesOrderFilter(OrderFilter): # Now we have a list of matching IDs, filter the queryset return queryset.filter(pk__in=sales_orders) + completed_before = InvenTreeDateFilter( + label=_('Completed Before'), field_name='shipment_date', lookup_expr='lt' + ) + + completed_after = InvenTreeDateFilter( + label=_('Completed After'), field_name='shipment_date', lookup_expr='gt' + ) + class SalesOrderMixin: """Mixin class for SalesOrder endpoints.""" @@ -1257,6 +1295,14 @@ class ReturnOrderFilter(OrderFilter): # Now we have a list of matching IDs, filter the queryset return queryset.filter(pk__in=return_orders) + completed_before = InvenTreeDateFilter( + label=_('Completed Before'), field_name='complete_date', lookup_expr='lt' + ) + + completed_after = InvenTreeDateFilter( + label=_('Completed After'), field_name='complete_date', lookup_expr='gt' + ) + class ReturnOrderMixin: """Mixin class for ReturnOrder endpoints.""" @@ -1325,6 +1371,7 @@ class ReturnOrderList(ReturnOrderMixin, DataExportViewMixin, ListCreateAPI): 'line_items', 'status', 'target_date', + 'complete_date', 'project_code', ] diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index 36663a7847..4f62be6d1d 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -1159,10 +1159,10 @@ class PartFilter(rest_filters.FilterSet): # Created date filters created_before = InvenTreeDateFilter( - label='Updated before', field_name='creation_date', lookup_expr='lte' + label='Updated before', field_name='creation_date', lookup_expr='lt' ) created_after = InvenTreeDateFilter( - label='Updated after', field_name='creation_date', lookup_expr='gte' + label='Updated after', field_name='creation_date', lookup_expr='gt' ) diff --git a/src/backend/InvenTree/stock/api.py b/src/backend/InvenTree/stock/api.py index 7734e101ab..42bc628d96 100644 --- a/src/backend/InvenTree/stock/api.py +++ b/src/backend/InvenTree/stock/api.py @@ -807,19 +807,28 @@ class StockFilter(rest_filters.FilterSet): # Update date filters updated_before = InvenTreeDateFilter( - label='Updated before', field_name='updated', lookup_expr='lte' + label=_('Updated before'), field_name='updated', lookup_expr='lt' ) + updated_after = InvenTreeDateFilter( - label='Updated after', field_name='updated', lookup_expr='gte' + label=_('Updated after'), field_name='updated', lookup_expr='gt' + ) + + stocktake_before = InvenTreeDateFilter( + label=_('Stocktake Before'), field_name='stocktake_date', lookup_expr='lt' + ) + + stocktake_after = InvenTreeDateFilter( + label=_('Stocktake After'), field_name='stocktake_date', lookup_expr='gt' ) # Stock "expiry" filters - expiry_date_lte = InvenTreeDateFilter( - label=_('Expiry date before'), field_name='expiry_date', lookup_expr='lte' + expiry_before = InvenTreeDateFilter( + label=_('Expiry date before'), field_name='expiry_date', lookup_expr='lt' ) - expiry_date_gte = InvenTreeDateFilter( - label=_('Expiry date after'), field_name='expiry_date', lookup_expr='gte' + expiry_after = InvenTreeDateFilter( + label=_('Expiry date after'), field_name='expiry_date', lookup_expr='gt' ) stale = rest_filters.BooleanFilter(label=_('Stale'), method='filter_stale') diff --git a/src/backend/InvenTree/templates/js/translated/table_filters.js b/src/backend/InvenTree/templates/js/translated/table_filters.js index 4706b493b5..a74ceaee30 100644 --- a/src/backend/InvenTree/templates/js/translated/table_filters.js +++ b/src/backend/InvenTree/templates/js/translated/table_filters.js @@ -421,11 +421,11 @@ function getStockTableFilters() { title: '{% trans "Has purchase price" %}', description: '{% trans "Show stock items which have a purchase price set" %}', }, - expiry_date_lte: { + expiry_before: { type: 'date', title: '{% trans "Expiry Date before" %}', }, - expiry_date_gte: { + expiry_after: { type: 'date', title: '{% trans "Expiry Date after" %}', }, diff --git a/src/frontend/src/pages/stock/LocationDetail.tsx b/src/frontend/src/pages/stock/LocationDetail.tsx index 9aaf256c2a..739ad8ba1f 100644 --- a/src/frontend/src/pages/stock/LocationDetail.tsx +++ b/src/frontend/src/pages/stock/LocationDetail.tsx @@ -3,8 +3,6 @@ import { Group, Skeleton, Stack, Text } from '@mantine/core'; import { IconInfoCircle, IconPackages, IconSitemap } from '@tabler/icons-react'; import { useMemo, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; - -import { ActionButton } from '../../components/buttons/ActionButton'; import AdminButton from '../../components/buttons/AdminButton'; import { PrintingActions } from '../../components/buttons/PrintingActions'; import { @@ -278,12 +276,6 @@ export default function Stock() { () => [ , , - } - onClick={notYetImplemented} - variant='outline' - size='lg' - />, location.pk ? ( void; +}) { + const setDateValue = useCallback( + (value: DateValue) => { + if (value) { + const date = value.toString(); + onValueChange(dayjs(date).format('YYYY-MM-DD')); + } else { + onValueChange(''); + } + }, + [onValueChange] + ); + + const [textValue, setTextValue] = useState(''); + + switch (filterType) { + case 'text': + return ( + onValueChange(textValue)} + > + + + } + onChange={(e) => setTextValue(e.currentTarget.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + onValueChange(textValue); + } + }} + /> + ); + case 'date': + return ( + + ); + case 'choice': + case 'boolean': + default: + return ( + setSelectedValue(value)} - maxDropdownHeight={800} - /> - ))} + {selectedFilter && ( + + )} ); } diff --git a/src/frontend/src/tables/build/BuildOrderTable.tsx b/src/frontend/src/tables/build/BuildOrderTable.tsx index 6e3d25ba87..01531866f0 100644 --- a/src/frontend/src/tables/build/BuildOrderTable.tsx +++ b/src/frontend/src/tables/build/BuildOrderTable.tsx @@ -25,12 +25,18 @@ import { } from '../ColumnRenderers'; import { AssignedToMeFilter, + CompletedAfterFilter, + CompletedBeforeFilter, + CreatedAfterFilter, + CreatedBeforeFilter, HasProjectCodeFilter, MaxDateFilter, MinDateFilter, OverdueFilter, StatusFilterOptions, - type TableFilter + type TableFilter, + TargetDateAfterFilter, + TargetDateBeforeFilter } from '../Filter'; import { InvenTreeTable } from '../InvenTreeTable'; @@ -130,6 +136,12 @@ export function BuildOrderTable({ AssignedToMeFilter(), MinDateFilter(), MaxDateFilter(), + CreatedBeforeFilter(), + CreatedAfterFilter(), + TargetDateBeforeFilter(), + TargetDateAfterFilter(), + CompletedBeforeFilter(), + CompletedAfterFilter(), { name: 'project_code', label: t`Project Code`, diff --git a/src/frontend/src/tables/purchasing/PurchaseOrderTable.tsx b/src/frontend/src/tables/purchasing/PurchaseOrderTable.tsx index 0f33d6e571..72c763b35d 100644 --- a/src/frontend/src/tables/purchasing/PurchaseOrderTable.tsx +++ b/src/frontend/src/tables/purchasing/PurchaseOrderTable.tsx @@ -14,6 +14,7 @@ import { useTable } from '../../hooks/UseTable'; import { apiUrl } from '../../states/ApiState'; import { useUserState } from '../../states/UserState'; import { + CompletionDateColumn, CreationDateColumn, DescriptionColumn, LineItemsProgressColumn, @@ -25,13 +26,19 @@ import { } from '../ColumnRenderers'; import { AssignedToMeFilter, + CompletedAfterFilter, + CompletedBeforeFilter, + CreatedAfterFilter, + CreatedBeforeFilter, HasProjectCodeFilter, MaxDateFilter, MinDateFilter, OutstandingFilter, OverdueFilter, StatusFilterOptions, - type TableFilter + type TableFilter, + TargetDateAfterFilter, + TargetDateBeforeFilter } from '../Filter'; import { InvenTreeTable } from '../InvenTreeTable'; @@ -64,6 +71,12 @@ export function PurchaseOrderTable({ AssignedToMeFilter(), MinDateFilter(), MaxDateFilter(), + CreatedBeforeFilter(), + CreatedAfterFilter(), + TargetDateBeforeFilter(), + TargetDateAfterFilter(), + CompletedBeforeFilter(), + CompletedAfterFilter(), { name: 'project_code', label: t`Project Code`, @@ -108,6 +121,9 @@ export function PurchaseOrderTable({ ProjectCodeColumn({}), CreationDateColumn({}), TargetDateColumn({}), + CompletionDateColumn({ + accessor: 'complete_date' + }), { accessor: 'total_price', title: t`Total Price`, diff --git a/src/frontend/src/tables/sales/ReturnOrderTable.tsx b/src/frontend/src/tables/sales/ReturnOrderTable.tsx index 8c62811ba9..d086b7ad6f 100644 --- a/src/frontend/src/tables/sales/ReturnOrderTable.tsx +++ b/src/frontend/src/tables/sales/ReturnOrderTable.tsx @@ -14,8 +14,8 @@ import { useTable } from '../../hooks/UseTable'; import { apiUrl } from '../../states/ApiState'; import { useUserState } from '../../states/UserState'; import { + CompletionDateColumn, CreationDateColumn, - DateColumn, DescriptionColumn, LineItemsProgressColumn, ProjectCodeColumn, @@ -26,13 +26,19 @@ import { } from '../ColumnRenderers'; import { AssignedToMeFilter, + CompletedAfterFilter, + CompletedBeforeFilter, + CreatedAfterFilter, + CreatedBeforeFilter, HasProjectCodeFilter, MaxDateFilter, MinDateFilter, OutstandingFilter, OverdueFilter, StatusFilterOptions, - type TableFilter + type TableFilter, + TargetDateAfterFilter, + TargetDateBeforeFilter } from '../Filter'; import { InvenTreeTable } from '../InvenTreeTable'; @@ -62,6 +68,12 @@ export function ReturnOrderTable({ AssignedToMeFilter(), MinDateFilter(), MaxDateFilter(), + CreatedBeforeFilter(), + CreatedAfterFilter(), + TargetDateBeforeFilter(), + TargetDateAfterFilter(), + CompletedBeforeFilter(), + CompletedAfterFilter(), { name: 'project_code', label: t`Project Code`, @@ -117,9 +129,8 @@ export function ReturnOrderTable({ ProjectCodeColumn({}), CreationDateColumn({}), TargetDateColumn({}), - DateColumn({ - accessor: 'complete_date', - title: t`Completion Date` + CompletionDateColumn({ + accessor: 'complete_date' }), ResponsibleColumn({}), { diff --git a/src/frontend/src/tables/sales/SalesOrderTable.tsx b/src/frontend/src/tables/sales/SalesOrderTable.tsx index 220eadb9a9..265ec9a214 100644 --- a/src/frontend/src/tables/sales/SalesOrderTable.tsx +++ b/src/frontend/src/tables/sales/SalesOrderTable.tsx @@ -27,13 +27,19 @@ import { } from '../ColumnRenderers'; import { AssignedToMeFilter, + CompletedAfterFilter, + CompletedBeforeFilter, + CreatedAfterFilter, + CreatedBeforeFilter, HasProjectCodeFilter, MaxDateFilter, MinDateFilter, OutstandingFilter, OverdueFilter, StatusFilterOptions, - type TableFilter + type TableFilter, + TargetDateAfterFilter, + TargetDateBeforeFilter } from '../Filter'; import { InvenTreeTable } from '../InvenTreeTable'; @@ -63,6 +69,12 @@ export function SalesOrderTable({ AssignedToMeFilter(), MinDateFilter(), MaxDateFilter(), + CreatedBeforeFilter(), + CreatedAfterFilter(), + TargetDateBeforeFilter(), + TargetDateAfterFilter(), + CompletedBeforeFilter(), + CompletedAfterFilter(), { name: 'project_code', label: t`Project Code`, diff --git a/src/frontend/src/tables/stock/StockItemTable.tsx b/src/frontend/src/tables/stock/StockItemTable.tsx index 276978cac0..62c0ff115e 100644 --- a/src/frontend/src/tables/stock/StockItemTable.tsx +++ b/src/frontend/src/tables/stock/StockItemTable.tsx @@ -286,7 +286,11 @@ function stockItemTableColumns(): TableColumn[] { /** * Construct a list of available filters for the stock item table */ -function stockItemTableFilters(): TableFilter[] { +function stockItemTableFilters({ + enableExpiry +}: { + enableExpiry: boolean; +}): TableFilter[] { return [ { name: 'active', @@ -354,15 +358,35 @@ function stockItemTableFilters(): TableFilter[] { label: t`Is Serialized`, description: t`Show items which have a serial number` }, - // TODO: serial - // TODO: serial_gte - // TODO: serial_lte + { + name: 'batch', + label: t`Batch Code`, + description: t`Filter items by batch code`, + type: 'text' + }, + { + name: 'serial', + label: t`Serial Number`, + description: t`Filter items by serial number`, + type: 'text' + }, + { + name: 'serial_lte', + label: t`Serial Number LTE`, + description: t`Show items with serial numbers less than or equal to a given value`, + type: 'text' + }, + { + name: 'serial_gte', + label: t`Serial Number GTE`, + description: t`Show items with serial numbers greater than or equal to a given value`, + type: 'text' + }, { name: 'has_batch', label: t`Has Batch Code`, description: t`Show items which have a batch code` }, - // TODO: batch { name: 'tracked', label: t`Tracked`, @@ -373,10 +397,56 @@ function stockItemTableFilters(): TableFilter[] { label: t`Has Purchase Price`, description: t`Show items which have a purchase price` }, - // TODO: Expired - // TODO: stale - // TODO: expiry_date_lte - // TODO: expiry_date_gte + { + name: 'expired', + label: t`Expired`, + description: t`Show items which have expired`, + active: enableExpiry + }, + { + name: 'stale', + label: t`Stale`, + description: t`Show items which are stale`, + active: enableExpiry + }, + { + name: 'expiry_before', + label: t`Expired Before`, + description: t`Show items which expired before this date`, + type: 'date', + active: enableExpiry + }, + { + name: 'expiry_after', + label: t`Expired After`, + description: t`Show items which expired after this date`, + type: 'date', + active: enableExpiry + }, + { + name: 'updated_before', + label: t`Updated Before`, + description: t`Show items updated before this date`, + type: 'date' + }, + { + name: 'updated_after', + label: t`Updated After`, + description: t`Show items updated after this date`, + type: 'date' + }, + { + name: 'stocktake_before', + label: t`Stocktake Before`, + description: t`Show items counted before this date`, + type: 'date' + }, + { + name: 'stocktake_after', + label: t`Stocktake After`, + description: t`Show items counted after this date`, + type: 'date' + }, { name: 'external', label: t`External Location`, @@ -397,12 +467,25 @@ export function StockItemTable({ allowAdd?: boolean; tableName: string; }>) { - const tableColumns = useMemo(() => stockItemTableColumns(), []); - const tableFilters = useMemo(() => stockItemTableFilters(), []); - const table = useTable(tableName); const user = useUserState(); + const settings = useGlobalSettingsState(); + + const stockExpiryEnabled = useMemo( + () => settings.isSet('STOCK_ENABLE_EXPIRY'), + [settings] + ); + + const tableColumns = useMemo(() => stockItemTableColumns(), []); + const tableFilters = useMemo( + () => + stockItemTableFilters({ + enableExpiry: stockExpiryEnabled + }), + [stockExpiryEnabled] + ); + const tableActionParams: StockOperationProps = useMemo(() => { return { items: table.selectedRecords, diff --git a/src/frontend/tests/helpers.ts b/src/frontend/tests/helpers.ts new file mode 100644 index 0000000000..e352881fe9 --- /dev/null +++ b/src/frontend/tests/helpers.ts @@ -0,0 +1,46 @@ +/** + * Open the filter drawer for the currently visible table + * @param page - The page object + */ +export const openFilterDrawer = async (page) => { + await page.getByLabel('table-select-filters').click(); +}; + +/** + * Close the filter drawer for the currently visible table + * @param page - The page object + */ +export const closeFilterDrawer = async (page) => { + await page.getByLabel('filter-drawer-close').click(); +}; + +/** + * Click the specified button (if it is visible) + * @param page - The page object + * @param name - The name of the button to click + */ +export const clickButtonIfVisible = async (page, name, timeout = 500) => { + await page.waitForTimeout(timeout); + + if (await page.getByRole('button', { name }).isVisible()) { + await page.getByRole('button', { name }).click(); + } +}; + +/** + * Clear all filters from the currently visible table + * @param page - The page object + */ +export const clearTableFilters = async (page) => { + await openFilterDrawer(page); + await clickButtonIfVisible(page, 'Clear Filters'); + await page.getByLabel('filter-drawer-close').click(); +}; + +/** + * Return the parent 'row' element for a given 'cell' element + * @param cell - The cell element + */ +export const getRowFromCell = async (cell) => { + return cell.locator('xpath=ancestor::tr').first(); +}; diff --git a/src/frontend/tests/pages/pui_build.spec.ts b/src/frontend/tests/pages/pui_build.spec.ts index 6d3126c910..ad2e7e38a6 100644 --- a/src/frontend/tests/pages/pui_build.spec.ts +++ b/src/frontend/tests/pages/pui_build.spec.ts @@ -1,8 +1,13 @@ import { test } from '../baseFixtures.ts'; import { baseUrl } from '../defaults.ts'; +import { + clickButtonIfVisible, + getRowFromCell, + openFilterDrawer +} from '../helpers.ts'; import { doQuickLogin } from '../login.ts'; -test('Pages - Build Order', async ({ page }) => { +test('Build Order - Basic Tests', async ({ page }) => { await doQuickLogin(page); await page.goto(`${baseUrl}/part/`); @@ -82,7 +87,7 @@ test('Pages - Build Order', async ({ page }) => { .waitFor(); }); -test('Pages - Build Order - Build Outputs', async ({ page }) => { +test('Build Order - Build Outputs', async ({ page }) => { await doQuickLogin(page); await page.goto(`${baseUrl}/part/`); @@ -140,7 +145,7 @@ test('Pages - Build Order - Build Outputs', async ({ page }) => { // Cancel one of the newly created outputs const cell = await page.getByRole('cell', { name: `# ${sn}` }); - const row = await cell.locator('xpath=ancestor::tr').first(); + const row = await getRowFromCell(cell); await row.getByLabel(/row-action-menu-/i).click(); await page.getByRole('menuitem', { name: 'Cancel' }).click(); await page.getByRole('button', { name: 'Submit' }).click(); @@ -148,7 +153,7 @@ test('Pages - Build Order - Build Outputs', async ({ page }) => { // Complete the other output const cell2 = await page.getByRole('cell', { name: `# ${sn + 1}` }); - const row2 = await cell2.locator('xpath=ancestor::tr').first(); + const row2 = await getRowFromCell(cell2); await row2.getByLabel(/row-action-menu-/i).click(); await page.getByRole('menuitem', { name: 'Complete' }).click(); await page.getByLabel('related-field-location').click(); @@ -158,7 +163,7 @@ test('Pages - Build Order - Build Outputs', async ({ page }) => { await page.getByText('Build outputs have been completed').waitFor(); }); -test('Pages - Build Order - Allocation', async ({ page }) => { +test('Build Order - Allocation', async ({ page }) => { await doQuickLogin(page); await page.goto(`${baseUrl}/manufacturing/build-order/1/line-items`); @@ -170,7 +175,7 @@ test('Pages - Build Order - Allocation', async ({ page }) => { // The capacitor stock should be fully allocated const cell = await page.getByRole('cell', { name: /C_1uF_0805/ }); - const row = await cell.locator('xpath=ancestor::tr').first(); + const row = await getRowFromCell(cell); await row.getByText(/150 \/ 150/).waitFor(); @@ -237,7 +242,7 @@ test('Pages - Build Order - Allocation', async ({ page }) => { const item = data[idx]; const cell = await page.getByRole('cell', { name: item.name }); - const row = await cell.locator('xpath=ancestor::tr').first(); + const row = await getRowFromCell(cell); const progress = `${item.allocated} / ${item.required}`; await row.getByRole('cell', { name: item.ipn }).first().waitFor(); @@ -257,3 +262,14 @@ test('Pages - Build Order - Allocation', async ({ page }) => { .getByRole('menuitem', { name: 'Deallocate Stock', exact: true }) .waitFor(); }); + +test('Build Order - Filters', async ({ page }) => { + await doQuickLogin(page); + + await page.goto(`${baseUrl}/manufacturing/index/buildorders`); + + await openFilterDrawer(page); + await clickButtonIfVisible(page, 'Clear Filters'); + + await page.waitForTimeout(2500); +}); diff --git a/src/frontend/tests/pages/pui_dashboard.spec.ts b/src/frontend/tests/pages/pui_dashboard.spec.ts index 3dddb14b48..3b0e376bf7 100644 --- a/src/frontend/tests/pages/pui_dashboard.spec.ts +++ b/src/frontend/tests/pages/pui_dashboard.spec.ts @@ -2,7 +2,7 @@ import { test } from '../baseFixtures.js'; import { doQuickLogin } from '../login.js'; import { setPluginState } from '../settings.js'; -test('Pages - Dashboard - Basic', async ({ page }) => { +test('Dashboard - Basic', async ({ page }) => { await doQuickLogin(page); await page.getByText('Use the menu to add widgets').waitFor(); @@ -35,7 +35,7 @@ test('Pages - Dashboard - Basic', async ({ page }) => { await page.getByLabel('dashboard-accept-layout').click(); }); -test('Pages - Dashboard - Plugins', async ({ page, request }) => { +test('Dashboard - Plugins', async ({ page, request }) => { // Ensure that the "SampleUI" plugin is enabled await setPluginState({ request, diff --git a/src/frontend/tests/pages/pui_part.spec.ts b/src/frontend/tests/pages/pui_part.spec.ts index 9629e43ec8..9f19892f03 100644 --- a/src/frontend/tests/pages/pui_part.spec.ts +++ b/src/frontend/tests/pages/pui_part.spec.ts @@ -1,5 +1,6 @@ import { test } from '../baseFixtures'; import { baseUrl } from '../defaults'; +import { getRowFromCell } from '../helpers'; import { doQuickLogin } from '../login'; /** @@ -129,9 +130,7 @@ test('Parts - Allocations', async ({ page }) => { // Check "progress" bar of BO0001 const build_order_cell = await page.getByRole('cell', { name: 'BO0001' }); - const build_order_row = await build_order_cell - .locator('xpath=ancestor::tr') - .first(); + const build_order_row = await getRowFromCell(build_order_cell); await build_order_row.getByText('11 / 75').waitFor(); // Expand allocations against BO0001 @@ -147,9 +146,7 @@ test('Parts - Allocations', async ({ page }) => { // Check "progress" bar of SO0025 const sales_order_cell = await page.getByRole('cell', { name: 'SO0025' }); - const sales_order_row = await sales_order_cell - .locator('xpath=ancestor::tr') - .first(); + const sales_order_row = await getRowFromCell(sales_order_cell); await sales_order_row.getByText('3 / 10').waitFor(); // Expand allocations against SO0025 diff --git a/src/frontend/tests/pages/pui_purchase_order.spec.ts b/src/frontend/tests/pages/pui_purchase_order.spec.ts index 2b94c80ac9..ff8207346d 100644 --- a/src/frontend/tests/pages/pui_purchase_order.spec.ts +++ b/src/frontend/tests/pages/pui_purchase_order.spec.ts @@ -1,4 +1,5 @@ import { test } from '../baseFixtures.ts'; +import { clickButtonIfVisible, openFilterDrawer } from '../helpers.ts'; import { doQuickLogin } from '../login.ts'; test('Purchase Orders - General', async ({ page }) => { @@ -51,6 +52,30 @@ test('Purchase Orders - General', async ({ page }) => { await page.getByRole('tab', { name: 'Details' }).waitFor(); }); +test('Purchase Orders - Filters', async ({ page }) => { + await doQuickLogin(page, 'reader', 'readonly'); + + await page.getByRole('tab', { name: 'Purchasing' }).click(); + await page.getByRole('tab', { name: 'Purchase Orders' }).click(); + + // Open filters drawer + await openFilterDrawer(page); + await clickButtonIfVisible(page, 'Clear Filters'); + + await page.getByRole('button', { name: 'Add Filter' }).click(); + + // Check for expected filter options + await page.getByPlaceholder('Select filter').fill('before'); + await page.getByRole('option', { name: 'Created Before' }).waitFor(); + await page.getByRole('option', { name: 'Completed Before' }).waitFor(); + await page.getByRole('option', { name: 'Target Date Before' }).waitFor(); + + await page.getByPlaceholder('Select filter').fill('after'); + await page.getByRole('option', { name: 'Created After' }).waitFor(); + await page.getByRole('option', { name: 'Completed After' }).waitFor(); + await page.getByRole('option', { name: 'Target Date After' }).waitFor(); +}); + /** * Tests for receiving items against a purchase order */ diff --git a/src/frontend/tests/pages/pui_stock.spec.ts b/src/frontend/tests/pages/pui_stock.spec.ts index df72be3887..3737250b87 100644 --- a/src/frontend/tests/pages/pui_stock.spec.ts +++ b/src/frontend/tests/pages/pui_stock.spec.ts @@ -1,8 +1,9 @@ import { test } from '../baseFixtures.js'; import { baseUrl } from '../defaults.js'; +import { clickButtonIfVisible, openFilterDrawer } from '../helpers.js'; import { doQuickLogin } from '../login.js'; -test('Stock', async ({ page }) => { +test('Stock - Basic Tests', async ({ page }) => { await doQuickLogin(page); await page.goto(`${baseUrl}/stock/location/index/`); @@ -49,6 +50,45 @@ test('Stock - Location Tree', async ({ page }) => { await page.getByRole('cell', { name: 'Factory' }).first().waitFor(); }); +test('Stock - Filters', async ({ page }) => { + await doQuickLogin(page, 'steven', 'wizardstaff'); + + await page.goto(`${baseUrl}/stock/location/index/`); + await page.getByRole('tab', { name: 'Stock Items' }).click(); + + await openFilterDrawer(page); + await clickButtonIfVisible(page, 'Clear Filters'); + + // Filter by updated date + await page.getByRole('button', { name: 'Add Filter' }).click(); + await page.getByPlaceholder('Select filter').fill('updated'); + await page.getByText('Updated After').click(); + await page.getByPlaceholder('Select date value').fill('2010-01-01'); + await page.getByText('Show items updated after this date').waitFor(); + + // Filter by batch code + await page.getByRole('button', { name: 'Add Filter' }).click(); + await page.getByPlaceholder('Select filter').fill('batch'); + await page + .getByRole('option', { name: 'Batch Code', exact: true }) + .locator('span') + .click(); + await page.getByPlaceholder('Enter filter value').fill('TABLE-B02'); + await page.getByLabel('apply-text-filter').click(); + + // Close dialog + await page.keyboard.press('Escape'); + + // Ensure correct result is displayed + await page + .getByRole('cell', { name: 'A round table - with blue paint' }) + .waitFor(); + + // Clear filters (ready for next set of tests) + await openFilterDrawer(page); + await clickButtonIfVisible(page, 'Clear Filters'); +}); + test('Stock - Serial Numbers', async ({ page }) => { await doQuickLogin(page); diff --git a/src/frontend/tests/pui_tables.spec.ts b/src/frontend/tests/pui_tables.spec.ts index 7c5bbaa41a..015023c443 100644 --- a/src/frontend/tests/pui_tables.spec.ts +++ b/src/frontend/tests/pui_tables.spec.ts @@ -1,23 +1,23 @@ import { test } from './baseFixtures.js'; import { baseUrl } from './defaults.js'; +import { + clearTableFilters, + closeFilterDrawer, + openFilterDrawer +} from './helpers.js'; import { doQuickLogin } from './login.js'; // Helper function to set the value of a specific table filter const setFilter = async (page, name: string, value: string) => { - await page.getByLabel('table-select-filters').click(); + await openFilterDrawer(page); + await page.getByRole('button', { name: 'Add Filter' }).click(); await page.getByPlaceholder('Select filter').click(); await page.getByRole('option', { name: name, exact: true }).click(); await page.getByPlaceholder('Select filter value').click(); await page.getByRole('option', { name: value, exact: true }).click(); - await page.getByLabel('filter-drawer-close').click(); -}; -// Helper function to clear table filters -const clearFilters = async (page) => { - await page.getByLabel('table-select-filters').click(); - await page.getByRole('button', { name: 'Clear Filters' }).click(); - await page.getByLabel('filter-drawer-close').click(); + await closeFilterDrawer(page); }; test('Tables - Filters', async ({ page }) => { @@ -30,14 +30,14 @@ test('Tables - Filters', async ({ page }) => { await setFilter(page, 'Responsible', 'allaccess'); await setFilter(page, 'Project Code', 'PRJ-NIM'); - await clearFilters(page); + await clearTableFilters(page); // Head to the "part list" page await page.goto(`${baseUrl}/part/category/index/parts/`); await setFilter(page, 'Assembly', 'Yes'); - await clearFilters(page); + await clearTableFilters(page); // Head to the "purchase order list" page await page.goto(`${baseUrl}/purchasing/index/purchaseorders/`); @@ -47,7 +47,7 @@ test('Tables - Filters', async ({ page }) => { await setFilter(page, 'Assigned to me', 'No'); await setFilter(page, 'Project Code', 'PRO-ZEN'); - await clearFilters(page); + await clearTableFilters(page); }); test('Tables - Columns', async ({ page }) => { From ee9980e481382133efe3a79ff6c3e38c7f6e9f02 Mon Sep 17 00:00:00 2001 From: Volker Date: Mon, 25 Nov 2024 12:02:22 +0100 Subject: [PATCH 04/19] after_save_stock_item (#8546) This pull request addresses the issue discussed in #8452 --- src/backend/InvenTree/stock/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/InvenTree/stock/models.py b/src/backend/InvenTree/stock/models.py index d4827e8fcb..a89051fdeb 100644 --- a/src/backend/InvenTree/stock/models.py +++ b/src/backend/InvenTree/stock/models.py @@ -2420,7 +2420,7 @@ def after_save_stock_item(sender, instance: StockItem, created, **kwargs): """Hook function to be executed after StockItem object is saved/updated.""" from part import tasks as part_tasks - if created and not InvenTree.ready.isImportingData(): + if not InvenTree.ready.isImportingData(): if InvenTree.ready.canAppAccessDatabase(allow_test=True): InvenTree.tasks.offload_task( part_tasks.notify_low_stock_if_required, From 51d981a102b0c999e7d390034453e38a135a6ebb Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 22:34:35 +1100 Subject: [PATCH 05/19] Add playwright tests (#8549) - Add checks for invalid logins --- .../components/forms/AuthenticationForm.tsx | 6 ++ src/frontend/tests/pui_basic.spec.ts | 54 ----------- src/frontend/tests/pui_login.spec.ts | 97 +++++++++++++++++++ 3 files changed, 103 insertions(+), 54 deletions(-) delete mode 100644 src/frontend/tests/pui_basic.spec.ts create mode 100644 src/frontend/tests/pui_login.spec.ts diff --git a/src/frontend/src/components/forms/AuthenticationForm.tsx b/src/frontend/src/components/forms/AuthenticationForm.tsx index cc75bb2d02..66057b5ae3 100644 --- a/src/frontend/src/components/forms/AuthenticationForm.tsx +++ b/src/frontend/src/components/forms/AuthenticationForm.tsx @@ -107,12 +107,14 @@ export function AuthenticationForm() { @@ -228,12 +230,14 @@ export function RegistrationForm() { diff --git a/src/frontend/tests/pui_basic.spec.ts b/src/frontend/tests/pui_basic.spec.ts deleted file mode 100644 index c1639caa36..0000000000 --- a/src/frontend/tests/pui_basic.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { expect, test } from './baseFixtures.js'; -import { baseUrl, user } from './defaults.js'; -import { doLogin, doQuickLogin } from './login.js'; - -test('Basic Login Test', async ({ page }) => { - await doLogin(page); - - // Check that the username is provided - await page.getByText(user.username); - - await expect(page).toHaveTitle(/^InvenTree/); - - // Go to the dashboard - await page.goto(baseUrl); - await page.waitForURL('**/platform'); - - await page.getByText('InvenTree Demo Server -').waitFor(); - - // Check that the username is provided - await page.getByText(user.username); - - await expect(page).toHaveTitle(/^InvenTree/); - - // Go to the dashboard - await page.goto(baseUrl); - await page.waitForURL('**/platform'); - - // Logout (via menu) - await page.getByRole('button', { name: 'Ally Access' }).click(); - await page.getByRole('menuitem', { name: 'Logout' }).click(); - - await page.waitForURL('**/platform/login'); - await page.getByLabel('username'); -}); - -test('Quick Login Test', async ({ page }) => { - await doQuickLogin(page); - - // Check that the username is provided - await page.getByText(user.username); - - await expect(page).toHaveTitle(/^InvenTree/); - - // Go to the dashboard - await page.goto(baseUrl); - await page.waitForURL('**/platform'); - - await page.getByText('InvenTree Demo Server - ').waitFor(); - - // Logout (via URL) - await page.goto(`${baseUrl}/logout/`); - await page.waitForURL('**/platform/login'); - await page.getByLabel('username'); -}); diff --git a/src/frontend/tests/pui_login.spec.ts b/src/frontend/tests/pui_login.spec.ts new file mode 100644 index 0000000000..90331a9ef5 --- /dev/null +++ b/src/frontend/tests/pui_login.spec.ts @@ -0,0 +1,97 @@ +import { expect, test } from './baseFixtures.js'; +import { baseUrl, logoutUrl, user } from './defaults.js'; +import { doLogin, doQuickLogin } from './login.js'; + +test('Login - Basic Test', async ({ page }) => { + await doLogin(page); + + // Check that the username is provided + await page.getByText(user.username); + + await expect(page).toHaveTitle(/^InvenTree/); + + // Go to the dashboard + await page.goto(baseUrl); + await page.waitForURL('**/platform'); + + await page.getByText('InvenTree Demo Server -').waitFor(); + + // Check that the username is provided + await page.getByText(user.username); + + await expect(page).toHaveTitle(/^InvenTree/); + + // Go to the dashboard + await page.goto(baseUrl); + await page.waitForURL('**/platform'); + + // Logout (via menu) + await page.getByRole('button', { name: 'Ally Access' }).click(); + await page.getByRole('menuitem', { name: 'Logout' }).click(); + + await page.waitForURL('**/platform/login'); + await page.getByLabel('username'); +}); + +test('Login - Quick Test', async ({ page }) => { + await doQuickLogin(page); + + // Check that the username is provided + await page.getByText(user.username); + + await expect(page).toHaveTitle(/^InvenTree/); + + // Go to the dashboard + await page.goto(baseUrl); + await page.waitForURL('**/platform'); + + await page.getByText('InvenTree Demo Server - ').waitFor(); + + // Logout (via URL) + await page.goto(`${baseUrl}/logout/`); + await page.waitForURL('**/platform/login'); + await page.getByLabel('username'); +}); + +/** + * Test various types of login failure + */ +test('Login - Failures', async ({ page }) => { + const loginWithError = async () => { + await page.getByRole('button', { name: 'Log In' }).click(); + await page.getByText('Login failed').waitFor(); + await page.getByText('Check your input and try again').waitFor(); + await page.locator('#login').getByRole('button').click(); + }; + + // Navigate to the 'login' page + await page.goto(logoutUrl); + await expect(page).toHaveTitle(/^InvenTree.*$/); + await page.waitForURL('**/platform/login'); + + // Attempt login with invalid credentials + await page.getByLabel('login-username').fill('invalid user'); + await page.getByLabel('login-password').fill('invalid password'); + + await loginWithError(); + + // Attempt login with valid (but disabled) user + await page.getByLabel('login-username').fill('ian'); + await page.getByLabel('login-password').fill('inactive'); + + await loginWithError(); + + // Attempt login with no username + await page.getByLabel('login-username').fill(''); + await page.getByLabel('login-password').fill('hunter2'); + + await loginWithError(); + + // Attempt login with no password + await page.getByLabel('login-username').fill('ian'); + await page.getByLabel('login-password').fill(''); + + await loginWithError(); + + await page.waitForTimeout(2500); +}); From d26a683cf12475c02006844cd17e647dccee9d81 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 22:43:17 +1100 Subject: [PATCH 06/19] Add unit test (#8550) - Unit test to ensure event is fired when stock item is created OR updated - Ref: https://github.com/inventree/InvenTree/pull/8546 - Ref: https://github.com/inventree/InvenTree/issues/8452 --- src/backend/InvenTree/stock/tests.py | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/backend/InvenTree/stock/tests.py b/src/backend/InvenTree/stock/tests.py index 27548c3806..c83e6bf274 100644 --- a/src/backend/InvenTree/stock/tests.py +++ b/src/backend/InvenTree/stock/tests.py @@ -951,6 +951,45 @@ class StockTest(StockTestBase): # Final purchase price should be the weighted average self.assertAlmostEqual(s1.purchase_price.amount, 16.875, places=3) + def test_notify_low_stock(self): + """Test that the 'notify_low_stock' task is triggered correctly.""" + FUNC_NAME = 'part.tasks.notify_low_stock_if_required' + + from django_q.models import OrmQ + + # Start from a blank slate + OrmQ.objects.all().delete() + + def check_func() -> bool: + """Check that the 'notify_low_stock_if_required' task has been triggered.""" + found = False + for task in OrmQ.objects.all(): + if task.func() == FUNC_NAME: + found = True + break + + # Clear the task queue (for the next test) + OrmQ.objects.all().delete() + + return found + + self.assertFalse(check_func()) + + part = Part.objects.first() + + # Create a new stock item for this part + item = StockItem.objects.create( + part=part, quantity=100, location=StockLocation.objects.first() + ) + + self.assertTrue(check_func()) + self.assertFalse(check_func()) + + # Re-count the stock item + item.stocktake(99, None) + + self.assertTrue(check_func()) + class StockBarcodeTest(StockTestBase): """Run barcode tests for the stock app.""" From 0fa7ed2742a32b81c2343ea8be71f3077777281a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 07:34:51 +1100 Subject: [PATCH 07/19] Bump the dependencies group with 5 updates (#8556) Bumps the dependencies group with 5 updates: | Package | From | To | | --- | --- | --- | | [docker/metadata-action](https://github.com/docker/metadata-action) | `5.5.1` | `5.6.1` | | [codecov/codecov-action](https://github.com/codecov/codecov-action) | `5.0.2` | `5.0.7` | | [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.17.7` | `0.17.8` | | [github/codeql-action](https://github.com/github/codeql-action) | `3.27.4` | `3.27.5` | | [crowdin/github-action](https://github.com/crowdin/github-action) | `2.3.0` | `2.4.0` | Updates `docker/metadata-action` from 5.5.1 to 5.6.1 - [Release notes](https://github.com/docker/metadata-action/releases) - [Commits](https://github.com/docker/metadata-action/compare/8e5442c4ef9f78752691e2d8f8d19755c6f78e81...369eb591f429131d6889c46b94e711f089e6ca96) Updates `codecov/codecov-action` from 5.0.2 to 5.0.7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/5c47607acb93fed5485fdbf7232e8a31425f672a...015f24e6818733317a2da2edd6290ab26238649a) Updates `anchore/sbom-action` from 0.17.7 to 0.17.8 - [Release notes](https://github.com/anchore/sbom-action/releases) - [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md) - [Commits](https://github.com/anchore/sbom-action/compare/fc46e51fd3cb168ffb36c6d1915723c47db58abb...55dc4ee22412511ee8c3142cbea40418e6cec693) Updates `github/codeql-action` from 3.27.4 to 3.27.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/ea9e4e37992a54ee68a9622e985e60c8e8f12d9f...f09c1c0a94de965c15400f5634aa42fac8fb8f88) Updates `crowdin/github-action` from 2.3.0 to 2.4.0 - [Release notes](https://github.com/crowdin/github-action/releases) - [Commits](https://github.com/crowdin/github-action/compare/2d540f18b0a416b1fbf2ee5be35841bd380fc1da...a9ffb7d5ac46eca1bb1f06656bf888b39462f161) --- updated-dependencies: - dependency-name: docker/metadata-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: anchore/sbom-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: crowdin/github-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yaml | 2 +- .github/workflows/qc_checks.yaml | 6 +++--- .github/workflows/release.yaml | 2 +- .github/workflows/scorecard.yaml | 2 +- .github/workflows/translations.yaml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index fa904df0b1..a102dbf764 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -157,7 +157,7 @@ jobs: - name: Extract Docker metadata if: github.event_name != 'pull_request' id: meta - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # pin@v5.5.1 + uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # pin@v5.6.1 with: images: | inventree/inventree diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 05de516f6b..a4dd8e17a5 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -308,7 +308,7 @@ jobs: - name: Coverage Tests run: invoke dev.test --coverage - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # pin@v5.0.2 + uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # pin@v5.0.7 if: always() with: token: ${{ secrets.CODECOV_TOKEN }} @@ -440,7 +440,7 @@ jobs: - name: Run Tests run: invoke dev.test --migrations --report --coverage - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # pin@v5.0.2 + uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # pin@v5.0.7 if: always() with: token: ${{ secrets.CODECOV_TOKEN }} @@ -545,7 +545,7 @@ jobs: if: always() run: cd src/frontend && npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --exclude-after-remap false - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # pin@v5.0.2 + uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # pin@v5.0.7 if: always() with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 52b3da2bb9..3e24cca50f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -49,7 +49,7 @@ jobs: - name: Build frontend run: cd src/frontend && npm run compile && npm run build - name: Create SBOM for frontend - uses: anchore/sbom-action@fc46e51fd3cb168ffb36c6d1915723c47db58abb # pin@v0 + uses: anchore/sbom-action@55dc4ee22412511ee8c3142cbea40418e6cec693 # pin@v0 with: artifact-name: frontend-build.spdx path: src/frontend diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index 5a91f078ef..ae0805af3f 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 + uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 with: sarif_file: results.sarif diff --git a/.github/workflows/translations.yaml b/.github/workflows/translations.yaml index 099967ce23..f713896857 100644 --- a/.github/workflows/translations.yaml +++ b/.github/workflows/translations.yaml @@ -51,7 +51,7 @@ jobs: git reset --hard git reset HEAD~ - name: crowdin action - uses: crowdin/github-action@2d540f18b0a416b1fbf2ee5be35841bd380fc1da # pin@v2 + uses: crowdin/github-action@a9ffb7d5ac46eca1bb1f06656bf888b39462f161 # pin@v2 with: upload_sources: true upload_translations: false From 0f194af585f70a74ca8b0987dcf8dce24a8ac73c Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Mon, 25 Nov 2024 22:29:47 +0100 Subject: [PATCH 08/19] Fix spelling of InvenTree in code base (#8561) * fix spelling of InvenTree in code * fix spelling in frontend --- contrib/container/Caddyfile | 6 +++--- docs/docs/features.md | 2 +- docs/docs/order/company.md | 2 +- docs/docs/releases/0.7.0.md | 2 +- docs/docs/start/advanced.md | 2 +- docs/docs/start/installer.md | 2 +- docs/docs/start/intro.md | 2 +- docs/docs/start/processes.md | 2 +- src/backend/InvenTree/InvenTree/helpers_mixin.py | 2 +- src/backend/InvenTree/plugin/builtin/suppliers/digikey.py | 4 ++-- src/backend/InvenTree/plugin/builtin/suppliers/lcsc.py | 4 ++-- src/backend/InvenTree/plugin/builtin/suppliers/mouser.py | 4 ++-- src/backend/InvenTree/plugin/builtin/suppliers/tme.py | 4 ++-- src/frontend/src/defaults/actions.tsx | 2 +- src/frontend/src/defaults/links.tsx | 2 +- src/frontend/src/states/states.tsx | 2 +- src/frontend/tests/modals.spec.ts | 2 +- src/frontend/tests/pui_command.spec.ts | 2 +- 18 files changed, 24 insertions(+), 24 deletions(-) diff --git a/contrib/container/Caddyfile b/contrib/container/Caddyfile index 96fb01c52a..b39c1c5be8 100644 --- a/contrib/container/Caddyfile +++ b/contrib/container/Caddyfile @@ -1,7 +1,7 @@ -# Example Caddyfile for Inventree +# Example Caddyfile for InvenTree # The following environment variables may be used: -# - INVENTREE_SITE_URL: The upstream URL of the Inventree site (default: inventree.localhost) -# - INVENTREE_SERVER: The internal URL of the Inventree container (default: http://inventree-server:8000) +# - INVENTREE_SITE_URL: The upstream URL of the InvenTree site (default: inventree.localhost) +# - INVENTREE_SERVER: The internal URL of the InvenTree container (default: http://inventree-server:8000) # # Note that while this file is a good starting point, it may need to be modified to suit your specific requirements diff --git a/docs/docs/features.md b/docs/docs/features.md index 4b5f99be0f..d40ee9209d 100644 --- a/docs/docs/features.md +++ b/docs/docs/features.md @@ -39,7 +39,7 @@ InvenTree allows you to upload simple BOM files in multiple formats, and downloa ## Build Parts -Inventree features a build management system to help you track the progress of your builds. +InvenTree features a build management system to help you track the progress of your builds. Builds consume stock items to make new parts, you can decide to automatically or manually allocate parts from your current inventory. [Read more...](./build/build.md) diff --git a/docs/docs/order/company.md b/docs/docs/order/company.md index 3e4d821046..4af748f8b2 100644 --- a/docs/docs/order/company.md +++ b/docs/docs/order/company.md @@ -61,7 +61,7 @@ A *contact* can be assigned to orders, (such as [purchase orders](./purchase_ord A company can have multiple registered addresses for use with all types of orders. An address is broken down to internationally recognised elements that are designed to allow for formatting an address according to user needs. -Addresses are composed differently across the world, and Inventree reflects this by splitting addresses into components: +Addresses are composed differently across the world, and InvenTree reflects this by splitting addresses into components: - Line 1: Main street address - Line 2: Extra street address line - Postal Code: Also known as ZIP code, this is normally a number 3-5 digits in length diff --git a/docs/docs/releases/0.7.0.md b/docs/docs/releases/0.7.0.md index 91eafd196f..0db1f66e00 100644 --- a/docs/docs/releases/0.7.0.md +++ b/docs/docs/releases/0.7.0.md @@ -81,7 +81,7 @@ Multiple improvements have been made to the docker installation process, most no ### QR code scanner -[#2779](https://github.com/inventree/InvenTree/pull/2779) provides a QR code scanner which can be used to quickly scan Inventree generated QR codes using webcams or mobile devices. This feature requires secure (HTTPS) connection to the server. +[#2779](https://github.com/inventree/InvenTree/pull/2779) provides a QR code scanner which can be used to quickly scan InvenTree generated QR codes using webcams or mobile devices. This feature requires secure (HTTPS) connection to the server. ### Order, Order diff --git a/docs/docs/start/advanced.md b/docs/docs/start/advanced.md index 7711eae331..14d8af5a3c 100644 --- a/docs/docs/start/advanced.md +++ b/docs/docs/start/advanced.md @@ -63,7 +63,7 @@ Next you can start configuring the connection. Either use the config file or set | `ldap.user_dn_template` | `INVENTREE_LDAP_USER_DN_TEMPLATE` | use direct bind as auth user, `ldap.bind_dn` and `ldap.bin_password` is not necessary then, e.g. `uid=%(user)s,dc=example,dc=org` | | `ldap.global_options` | `INVENTREE_LDAP_GLOBAL_OPTIONS` | set advanced options as dict, e.g. TLS settings. For a list of all available options, see [python-ldap docs](https://www.python-ldap.org/en/latest/reference/ldap.html#ldap-options). (keys and values starting with OPT_ get automatically converted to `python-ldap` keys) | | `ldap.search_filter_str`| `INVENTREE_LDAP_SEARCH_FILTER_STR` | LDAP search filter str, default: `uid=%(user)s` | -| `ldap.user_attr_map` | `INVENTREE_LDAP_USER_ATTR_MAP` | LDAP <-> Inventree user attribute map, can be json if used as env, in yml directly specify the object. default: `{"first_name": "givenName", "last_name": "sn", "email": "mail"}` | +| `ldap.user_attr_map` | `INVENTREE_LDAP_USER_ATTR_MAP` | LDAP <-> InvenTree user attribute map, can be json if used as env, in yml directly specify the object. default: `{"first_name": "givenName", "last_name": "sn", "email": "mail"}` | | `ldap.always_update_user` | `INVENTREE_LDAP_ALWAYS_UPDATE_USER` | Always update the user on each login, default: `true` | | `ldap.cache_timeout` | `INVENTREE_LDAP_CACHE_TIMEOUT` | cache timeout to reduce traffic with LDAP server, default: `3600` (1h) | | `ldap.group_search` | `INVENTREE_LDAP_GROUP_SEARCH` | Base LDAP DN for group searching; required to enable group features | diff --git a/docs/docs/start/installer.md b/docs/docs/start/installer.md index 6676124478..220e30a93a 100644 --- a/docs/docs/start/installer.md +++ b/docs/docs/start/installer.md @@ -31,7 +31,7 @@ The installer creates the following directories: | --- | --- | | `/etc/inventree/` | Configuration files | | `/opt/inventree/` | InvenTree application files | -| `/opt/inventree/data/` | Inventree data files | +| `/opt/inventree/data/` | InvenTree data files | #### Performed steps diff --git a/docs/docs/start/intro.md b/docs/docs/start/intro.md index 228641b55b..3b984a5443 100644 --- a/docs/docs/start/intro.md +++ b/docs/docs/start/intro.md @@ -68,7 +68,7 @@ python3 -m venv env The virtual environment needs to be activated to ensure the correct python binaries and libraries are used. The InvenTree instructions assume that the virtual environment is always correctly activated. -To configure Inventree inside a virtual environment, ``cd`` into the inventree base directory and run the following command: +To configure InvenTree inside a virtual environment, ``cd`` into the inventree base directory and run the following command: ``` source env/bin/activate diff --git a/docs/docs/start/processes.md b/docs/docs/start/processes.md index de74df2937..2784a1f613 100644 --- a/docs/docs/start/processes.md +++ b/docs/docs/start/processes.md @@ -100,4 +100,4 @@ InvenTree uses the [Redis](https://redis.io/) cache server to manage cache data. To optimize and configure your redis deployment follow the [official docker guide](https://redis.io/docs/getting-started/install-stack/docker/#configuration). !!! tip "Enable Cache" - While a redis container is provided in the default configuration, by default it is not enabled in the Inventree server. You can enable redis cache support by following the [caching configuration guide](./config.md#caching) + While a redis container is provided in the default configuration, by default it is not enabled in the InvenTree server. You can enable redis cache support by following the [caching configuration guide](./config.md#caching) diff --git a/src/backend/InvenTree/InvenTree/helpers_mixin.py b/src/backend/InvenTree/InvenTree/helpers_mixin.py index fee2ace924..7f4495ff50 100644 --- a/src/backend/InvenTree/InvenTree/helpers_mixin.py +++ b/src/backend/InvenTree/InvenTree/helpers_mixin.py @@ -99,7 +99,7 @@ class ClassProviderMixin: @classmethod def get_is_builtin(cls): - """Is this Class build in the Inventree source code?""" + """Is this Class build in the InvenTree source code?""" try: Path(cls.get_provider_file()).relative_to(settings.BASE_DIR) return True diff --git a/src/backend/InvenTree/plugin/builtin/suppliers/digikey.py b/src/backend/InvenTree/plugin/builtin/suppliers/digikey.py index 58215b01fc..180a25bea5 100644 --- a/src/backend/InvenTree/plugin/builtin/suppliers/digikey.py +++ b/src/backend/InvenTree/plugin/builtin/suppliers/digikey.py @@ -1,4 +1,4 @@ -"""The DigiKeyPlugin is meant to integrate the DigiKey API into Inventree. +"""The DigiKeyPlugin is meant to integrate the DigiKey API into InvenTree. This plugin can currently only match DigiKey barcodes to supplier parts. """ @@ -10,7 +10,7 @@ from plugin.mixins import SettingsMixin, SupplierBarcodeMixin class DigiKeyPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin): - """Plugin to integrate the DigiKey API into Inventree.""" + """Plugin to integrate the DigiKey API into InvenTree.""" NAME = 'DigiKeyPlugin' TITLE = _('Supplier Integration - DigiKey') diff --git a/src/backend/InvenTree/plugin/builtin/suppliers/lcsc.py b/src/backend/InvenTree/plugin/builtin/suppliers/lcsc.py index 40d27b7c16..e52f406bd9 100644 --- a/src/backend/InvenTree/plugin/builtin/suppliers/lcsc.py +++ b/src/backend/InvenTree/plugin/builtin/suppliers/lcsc.py @@ -1,4 +1,4 @@ -"""The LCSCPlugin is meant to integrate the LCSC API into Inventree. +"""The LCSCPlugin is meant to integrate the LCSC API into InvenTree. This plugin can currently only match LCSC barcodes to supplier parts. """ @@ -12,7 +12,7 @@ from plugin.mixins import SettingsMixin, SupplierBarcodeMixin class LCSCPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin): - """Plugin to integrate the LCSC API into Inventree.""" + """Plugin to integrate the LCSC API into InvenTree.""" NAME = 'LCSCPlugin' TITLE = _('Supplier Integration - LCSC') diff --git a/src/backend/InvenTree/plugin/builtin/suppliers/mouser.py b/src/backend/InvenTree/plugin/builtin/suppliers/mouser.py index b44ec94b59..47825ba900 100644 --- a/src/backend/InvenTree/plugin/builtin/suppliers/mouser.py +++ b/src/backend/InvenTree/plugin/builtin/suppliers/mouser.py @@ -1,4 +1,4 @@ -"""The MouserPlugin is meant to integrate the Mouser API into Inventree. +"""The MouserPlugin is meant to integrate the Mouser API into InvenTree. This plugin currently only match Mouser barcodes to supplier parts. """ @@ -10,7 +10,7 @@ from plugin.mixins import SettingsMixin, SupplierBarcodeMixin class MouserPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin): - """Plugin to integrate the Mouser API into Inventree.""" + """Plugin to integrate the Mouser API into InvenTree.""" NAME = 'MouserPlugin' TITLE = _('Supplier Integration - Mouser') diff --git a/src/backend/InvenTree/plugin/builtin/suppliers/tme.py b/src/backend/InvenTree/plugin/builtin/suppliers/tme.py index 8320a9037f..f614765ad0 100644 --- a/src/backend/InvenTree/plugin/builtin/suppliers/tme.py +++ b/src/backend/InvenTree/plugin/builtin/suppliers/tme.py @@ -1,4 +1,4 @@ -"""The TMEPlugin is meant to integrate the TME API into Inventree. +"""The TMEPlugin is meant to integrate the TME API into InvenTree. This plugin can currently only match TME barcodes to supplier parts. """ @@ -12,7 +12,7 @@ from plugin.mixins import SettingsMixin, SupplierBarcodeMixin class TMEPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin): - """Plugin to integrate the TME API into Inventree.""" + """Plugin to integrate the TME API into InvenTree.""" NAME = 'TMEPlugin' TITLE = _('Supplier Integration - TME') diff --git a/src/frontend/src/defaults/actions.tsx b/src/frontend/src/defaults/actions.tsx index e762f98004..b15d469222 100644 --- a/src/frontend/src/defaults/actions.tsx +++ b/src/frontend/src/defaults/actions.tsx @@ -38,7 +38,7 @@ export function getActions(navigate: NavigateFunction) { { id: 'server-info', label: t`Server Information`, - description: t`About this Inventree instance`, + description: t`About this InvenTree instance`, onClick: () => serverInfo(), leftSection: }, diff --git a/src/frontend/src/defaults/links.tsx b/src/frontend/src/defaults/links.tsx index 45336d22e5..e81c21875d 100644 --- a/src/frontend/src/defaults/links.tsx +++ b/src/frontend/src/defaults/links.tsx @@ -115,7 +115,7 @@ export function AboutLinks(): MenuLinkItem[] { { id: 'instance', title: t`System Information`, - description: t`About this Inventree instance`, + description: t`About this InvenTree instance`, icon: 'info', action: serverInfo }, diff --git a/src/frontend/src/states/states.tsx b/src/frontend/src/states/states.tsx index a88c9134bd..e0ca580930 100644 --- a/src/frontend/src/states/states.tsx +++ b/src/frontend/src/states/states.tsx @@ -92,7 +92,7 @@ export interface SettingChoice { } export enum SettingTyp { - Inventree = 'inventree', + InvenTree = 'inventree', Plugin = 'plugin', User = 'user', Notification = 'notification' diff --git a/src/frontend/tests/modals.spec.ts b/src/frontend/tests/modals.spec.ts index b9809ce538..f95d75eb8a 100644 --- a/src/frontend/tests/modals.spec.ts +++ b/src/frontend/tests/modals.spec.ts @@ -8,7 +8,7 @@ test('Modals as admin', async ({ page }) => { await page.getByLabel('open-spotlight').click(); await page .getByRole('button', { - name: 'Server Information About this Inventree instance' + name: 'Server Information About this InvenTree instance' }) .click(); await page.getByRole('cell', { name: 'Instance Name' }).waitFor(); diff --git a/src/frontend/tests/pui_command.spec.ts b/src/frontend/tests/pui_command.spec.ts index 8e2e2f7a98..f5144e0acb 100644 --- a/src/frontend/tests/pui_command.spec.ts +++ b/src/frontend/tests/pui_command.spec.ts @@ -49,7 +49,7 @@ test('Quick Command - No Keys', async ({ page }) => { await page.getByLabel('open-spotlight').click(); await page .getByRole('button', { - name: 'Server Information About this Inventree instance' + name: 'Server Information About this InvenTree instance' }) .click(); await page.getByRole('cell', { name: 'Instance Name' }).waitFor(); From 5cda270e4b34da82897071baeebabf704c69f6c9 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Mon, 25 Nov 2024 23:15:44 +0100 Subject: [PATCH 09/19] Small SAST fixes (#8534) * fix various middle-high SAST errors * fix another small issue * add default --- src/frontend/src/components/forms/ApiForm.tsx | 2 +- src/frontend/src/components/forms/fields/DateField.tsx | 2 +- src/frontend/src/components/importer/ImporterDrawer.tsx | 3 ++- src/frontend/src/components/plugins/PluginUIFeature.tsx | 4 ++-- src/frontend/src/forms/StockForms.tsx | 2 +- src/frontend/src/tables/part/ParametricPartTable.tsx | 8 +++----- src/frontend/src/tables/settings/TemplateTable.tsx | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/frontend/src/components/forms/ApiForm.tsx b/src/frontend/src/components/forms/ApiForm.tsx index 3e6a5abf8b..fa1c07b5a1 100644 --- a/src/frontend/src/components/forms/ApiForm.tsx +++ b/src/frontend/src/components/forms/ApiForm.tsx @@ -219,7 +219,7 @@ export function ApiForm({ // If the user has specified initial data, that overrides default values // But, *only* for the fields we have specified if (props.initialData) { - Object.keys(props.initialData).map((key) => { + Object.keys(props.initialData).forEach((key) => { if (key in defaultValuesMap) { defaultValuesMap[key] = props?.initialData?.[key] ?? defaultValuesMap[key]; diff --git a/src/frontend/src/components/forms/fields/DateField.tsx b/src/frontend/src/components/forms/fields/DateField.tsx index a0aaee289e..a497be516d 100644 --- a/src/frontend/src/components/forms/fields/DateField.tsx +++ b/src/frontend/src/components/forms/fields/DateField.tsx @@ -43,7 +43,7 @@ export default function DateField({ let dv: Date | null = null; if (field.value) { - dv = new Date(field.value) ?? null; + dv = new Date(field.value); } // Ensure that the date is valid diff --git a/src/frontend/src/components/importer/ImporterDrawer.tsx b/src/frontend/src/components/importer/ImporterDrawer.tsx index f687191605..875e0abe2e 100644 --- a/src/frontend/src/components/importer/ImporterDrawer.tsx +++ b/src/frontend/src/components/importer/ImporterDrawer.tsx @@ -70,7 +70,6 @@ export default function ImporterDrawer({ // Map from import steps to stepper steps const currentStep = useMemo(() => { switch (session.status) { - default: case importSessionStatus.INITIAL: return 0; case importSessionStatus.MAPPING: @@ -81,6 +80,8 @@ export default function ImporterDrawer({ return 3; case importSessionStatus.COMPLETE: return 4; + default: + return 0; } }, [session.status]); diff --git a/src/frontend/src/components/plugins/PluginUIFeature.tsx b/src/frontend/src/components/plugins/PluginUIFeature.tsx index 15ecfee337..c8a35c958e 100644 --- a/src/frontend/src/components/plugins/PluginUIFeature.tsx +++ b/src/frontend/src/components/plugins/PluginUIFeature.tsx @@ -84,7 +84,7 @@ export const getPluginTemplateEditor = ( useEffect(() => { (async () => { try { - await func({ + func({ ref: elRef.current!, registerHandlers: ({ getCode, setCode }) => { setCodeRef.current = setCode; @@ -136,7 +136,7 @@ export const getPluginTemplatePreview = ( useEffect(() => { (async () => { try { - await func({ + func({ ref: elRef.current!, registerHandlers: ({ updatePreview }) => { updatePreviewRef.current = updatePreview; diff --git a/src/frontend/src/forms/StockForms.tsx b/src/frontend/src/forms/StockForms.tsx index f52e547b11..53775e75b3 100644 --- a/src/frontend/src/forms/StockForms.tsx +++ b/src/frontend/src/forms/StockForms.tsx @@ -159,7 +159,7 @@ export function useStockFields({ hidden: create || partInstance.trackable == false || - (!stockItem?.quantity != undefined && stockItem?.quantity != 1) + (stockItem?.quantity != undefined && stockItem?.quantity != 1) }, batch: { placeholder: nextBatchCode diff --git a/src/frontend/src/tables/part/ParametricPartTable.tsx b/src/frontend/src/tables/part/ParametricPartTable.tsx index cf802657b5..8381622177 100644 --- a/src/frontend/src/tables/part/ParametricPartTable.tsx +++ b/src/frontend/src/tables/part/ParametricPartTable.tsx @@ -283,12 +283,10 @@ export default function ParametricPartTable({ if (column?.accessor?.toString()?.startsWith('parameter_')) { const col = column as any; onParameterClick(col.extra.template, record); - } else { + } else if (record?.pk) { // Navigate through to the part detail page - if (record?.pk) { - const url = getDetailUrl(ModelType.part, record.pk); - navigateToLink(url, navigate, event); - } + const url = getDetailUrl(ModelType.part, record.pk); + navigateToLink(url, navigate, event); } } }} diff --git a/src/frontend/src/tables/settings/TemplateTable.tsx b/src/frontend/src/tables/settings/TemplateTable.tsx index 81763823bf..70b86cd6bb 100644 --- a/src/frontend/src/tables/settings/TemplateTable.tsx +++ b/src/frontend/src/tables/settings/TemplateTable.tsx @@ -236,7 +236,7 @@ export function TemplateTable({ sortable: false, switchable: true }, - ...Object.entries(additionalFormFields || {})?.map(([key, field]) => ({ + ...Object.entries(additionalFormFields || {}).map(([key, field]) => ({ accessor: key, ...field, title: field.label, From 594dc49b84284db71aa2504db2eb65c22910dac7 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Mon, 25 Nov 2024 23:25:06 +0100 Subject: [PATCH 10/19] Bump backend deps (#8559) * bump backend deps * bump api --- contrib/container/requirements.txt | 116 +- contrib/dev_reqs/requirements.txt | 314 +-- .../InvenTree/InvenTree/api_version.py | 5 +- src/backend/requirements-dev.txt | 246 +-- src/backend/requirements.txt | 1798 +++++++++-------- 5 files changed, 1259 insertions(+), 1220 deletions(-) diff --git a/contrib/container/requirements.txt b/contrib/container/requirements.txt index 1d791af1a8..ccb367d006 100644 --- a/contrib/container/requirements.txt +++ b/contrib/container/requirements.txt @@ -10,9 +10,9 @@ django==4.2.16 \ # via # -r contrib/container/requirements.in # django-auth-ldap -django-auth-ldap==4.8.0 \ - --hash=sha256:4b4b944f3c28bce362f33fb6e8db68429ed8fd8f12f0c0c4b1a4344a7ef225ce \ - --hash=sha256:604250938ddc9fda619f247c7a59b0b2f06e53a7d3f46a156f28aa30dd71a738 +django-auth-ldap==5.1.0 \ + --hash=sha256:9c607e8d9c53cf2a0ccafbe0acfc33eb1d1fd474c46ec52d30aee0dca1da9668 \ + --hash=sha256:a5f7bdb54b2ab80e4e9eb080cd3e06e89e4c9d2d534ddb39b66cd970dd6d3536 # via -r contrib/container/requirements.in gunicorn==23.0.0 \ --hash=sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d \ @@ -22,32 +22,32 @@ invoke==2.2.0 \ --hash=sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820 \ --hash=sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5 # via -r contrib/container/requirements.in -mariadb==1.1.10 \ - --hash=sha256:03d6284ef713d1cad40146576a4cc2d6cbc1662060f2a0e59b174e1694521698 \ - --hash=sha256:1ce87971c02375236ff8933e6c593c748e7b2f2950b86eabfab4289fd250ea63 \ - --hash=sha256:1d81b22efbaaf4c5bc5e4cc4e2ef3c459538c1a939371089d8c5591d6f26a62e \ - --hash=sha256:29040e426f877ddc45f337c6eb381b6bbab63cc6bf8431a28effe30162142513 \ - --hash=sha256:4521aa721f926946bd71491f872e8babc78fa97755ed2114f5684b77363107cb \ - --hash=sha256:49200378c614984f5ec875481662a49d7c97c2be27970b01b32fa4b7520d4e22 \ - --hash=sha256:5d652117e2fdf12b9723e7452a05fce9e6ccbae6ea48871b21a3a8fde259dc48 \ - --hash=sha256:8c8c6b27486b0e1772a23002c702b5fd244eecf9f05633dd6cb345fc26755a20 \ - --hash=sha256:a332893e3ef7ceb7970ab4bd7c844bcb4bd68a051ca51313566f9808d7411f2d \ - --hash=sha256:d7b09ec4abd02ed235257feb769f90cd4066e8f536b55b92f5166103d5b66a63 \ - --hash=sha256:dff8b28ce4044574870d7bdd2d9f9f5da8e5f95a7ff6d226185db733060d1a93 +mariadb==1.1.11 \ + --hash=sha256:0f8de8d66ca71bd102f34a970a331b7d75bdf7f8050d80e37cdcc6ff3c85cf7a \ + --hash=sha256:2e72ea65f1d7d8563ee84e172f2a583193092bdb6ff83c470ca9722873273ecc \ + --hash=sha256:3f64b520089cb60c4f8302f365ed0ae057c4c859ab70fc8b1c4358192c3c8f27 \ + --hash=sha256:579420293fa790d5ae0a6cb4bdb7e8be8facc2ceefb6123c2b0e8042b3fa725d \ + --hash=sha256:6f28d8ccc597a3a1368be14078110f743900dbb3b0c7f1cce3072d83bec59c8a \ + --hash=sha256:c1992ebf9c6f012ac158e33fef9f2c4ba899f721064c4ae3a3489233793296c0 \ + --hash=sha256:cf6647cee081e21d0994b409ba8c8fa2077f3972f1de3627c5502fb31d14f806 \ + --hash=sha256:d7302ccd15f0beee7b286885cbf6ac71ddc240374691d669784d99f89ba34d79 \ + --hash=sha256:dbc4cf0e302ca82d46f9431a0b04f048e9c21ee56d6f3162c29605f84d63b40c \ + --hash=sha256:e94f1738bec09c97b601ddbb1908eb24524ba4630f507a775d82ffdb6c5794b3 \ + --hash=sha256:f6dfdc954edf02b6519419a054798cda6034dc459d1d482e3329e37aa27d34f0 # via -r contrib/container/requirements.in -mysqlclient==2.2.5 \ - --hash=sha256:1d2e2ca0fe8405d8d6464edd01bf059951279e4bc27284d39341bd4737b2bc64 \ - --hash=sha256:3f9625bea2b9bcde0ace76b32708762d44597491092c819fd1bff5b4e27f709b \ - --hash=sha256:8012c633aab8c91ea8172ac479807135b171501b9cad1a7cd9b58c4dc8dcdab5 \ - --hash=sha256:add8643c32f738014d252d2bdebb478623b04802e8396d5903905db36474d3ff \ - --hash=sha256:aee14f1872114865679fcb09aac3772de4595fa7dcf2f83a4c7afee15e508854 \ - --hash=sha256:b54511648c1455b43ac28f8b4c1f732c5b0c343e87f7a3bd6fc9f9fe0f91934e \ - --hash=sha256:b78438314199504c64f69e1e3521f2c9b419f19fcd85158b44c997b64409a6af \ - --hash=sha256:e871ede4261d0d42b8ed20a2459db411c7deafedd8e77b7e4ba760be4a6a752b +mysqlclient==2.2.6 \ + --hash=sha256:3da70a07753ba6be881f7d75e795e254f6a0c12795778034acc69769b0649d37 \ + --hash=sha256:43c5b30be0675080b9c815f457d73397f0442173e7be83d089b126835e2617ae \ + --hash=sha256:794857bce4f9a1903a99786dd29ad7887f45a870b3d11585b8c51c4a753c4174 \ + --hash=sha256:b0a5cddf1d3488b254605041070086cac743401d876a659a72d706a0d89c8ebb \ + --hash=sha256:c0b46d9b78b461dbb62482089ca8040fa916595b1b30f831ebbd1b0a82b43d53 \ + --hash=sha256:e940b41d85dfd7b190fa47d52f525f878cfa203d4653bf6a35b271b3c3be125b \ + --hash=sha256:e94a92858203d97fd584bdb6d7ee8c56f2590db8d77fd44215c0dcf5e739bc37 \ + --hash=sha256:f3efb849d6f7ef4b9788a0eda2e896b975e0ebf1d6bf3dcabea63fd698e5b0b5 # via -r contrib/container/requirements.in -packaging==24.1 \ - --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ - --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 +packaging==24.2 \ + --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ + --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f # via # gunicorn # mariadb @@ -121,9 +121,9 @@ psycopg-binary==3.2.3 \ --hash=sha256:fd65774ed7d65101b314808b6893e1a75b7664f680c3ef18d2e5c84d570fa393 \ --hash=sha256:fda0162b0dbfa5eaed6cdc708179fa27e148cb8490c7d62e5cf30713909658ea # via psycopg -psycopg-pool==3.2.3 \ - --hash=sha256:53bd8e640625e01b2927b2ad96df8ed8e8f91caea4597d45e7673fc7bbb85eb1 \ - --hash=sha256:bb942f123bef4b7fbe4d55421bd3fb01829903c95c0f33fd42b7e94e5ac9b52a +psycopg-pool==3.2.4 \ + --hash=sha256:61774b5bbf23e8d22bedc7504707135aaf744679f8ef9b3fe29942920746a6ed \ + --hash=sha256:f6a22cff0f21f06d72fb2f5cb48c618946777c49385358e0c88d062c59cbd224 # via psycopg pyasn1==0.6.1 \ --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ @@ -195,13 +195,13 @@ pyyaml==6.0.2 \ --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \ --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4 # via -r contrib/container/requirements.in -setuptools==75.2.0 \ - --hash=sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec \ - --hash=sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8 +setuptools==75.6.0 \ + --hash=sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6 \ + --hash=sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d # via -r contrib/container/requirements.in -sqlparse==0.5.1 \ - --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ - --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e +sqlparse==0.5.2 \ + --hash=sha256:9e37b35e16d1cc652a2545f0997c1deb23ea28fa1f3eefe609eee3063c3b105f \ + --hash=sha256:e99bc85c78160918c3e1d9230834ab8d80fc06c59d03f8db2618f65f65dda55e # via django typing-extensions==4.12.2 \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ @@ -209,27 +209,27 @@ typing-extensions==4.12.2 \ # via # psycopg # psycopg-pool -uv==0.4.25 \ - --hash=sha256:18100f0f36419a154306ed6211e3490bf18384cdf3f1a0950848bf64b62fa251 \ - --hash=sha256:2d29a78f011ecc2f31c13605acb6574c2894c06d258b0f8d0dbb899986800450 \ - --hash=sha256:2fc35b5273f1e018aecd66b70e0fd7d2eb6698853dde3e2fc644e7ebf9f825b1 \ - --hash=sha256:3d7680795ea78cdbabbcce73d039b2651cf1fa635ddc1aa3082660f6d6255c50 \ - --hash=sha256:4c55040e67470f2b73e95e432aba06f103a0b348ea0b9c6689b1029c8d9e89fd \ - --hash=sha256:50c7d0d9e7f392f81b13bf3b7e37768d1486f2fc9d533a54982aa0ed11e4db23 \ - --hash=sha256:578ae385fad6bd6f3868828e33d54994c716b315b1bc49106ec1f54c640837e4 \ - --hash=sha256:6e981b1465e30102e41946adede9cb08051a5d70c6daf09f91a7ea84f0b75c08 \ - --hash=sha256:7d266e02fefef930609328c31c075084295c3cb472bab3f69549fad4fd9d82b3 \ - --hash=sha256:94fb2b454afa6bdfeeea4b4581c878944ca9cf3a13712e6762f245f5fbaaf952 \ - --hash=sha256:a7022a71ff63a3838796f40e954b76bf7820fc27e96fe002c537e75ff8e34f1d \ - --hash=sha256:a7c3a18c20ddb527d296d1222bddf42b78031c50b5b4609d426569b5fb61f5b0 \ - --hash=sha256:aae9dcafd20d5ba978c8a4939ab942e8e2e155c109e9945207fbbd81d2892c9e \ - --hash=sha256:bdbfd0c476b9e80a3f89af96aed6dd7d2782646311317a9c72614ccce99bb2ad \ - --hash=sha256:be2a4fc4fcade9ea5e67e51738c95644360d6e59b6394b74fc579fb617f902f7 \ - --hash=sha256:d39077cdfe3246885fcdf32e7066ae731a166101d063629f9cea08738f79e6a3 \ - --hash=sha256:e02afb0f6d4b58718347f7d7cfa5a801e985ce42181ba971ed85ef149f6658ca \ - --hash=sha256:ec181be2bda10651a3558156409ac481549983e0276d0e3645e3b1464e7f8715 +uv==0.5.4 \ + --hash=sha256:05b45c7eefb178dcdab0d49cd642fb7487377d00727102a8d6d306cc034c0d83 \ + --hash=sha256:2118bb99cbc9787cb5e5cc4a507201e25a3fe88a9f389e8ffb84f242d96038c2 \ + --hash=sha256:30ce031e36c54d4ba791d743d992d0a4fd8d70480db781d30a2f6f5125f39194 \ + --hash=sha256:4432215deb8d5c1ccab17ee51cb80f5de1a20865ee02df47532f87442a3d6a58 \ + --hash=sha256:493aedc3c758bbaede83ecc8d5f7e6a9279ebec151c7f756aa9ea898c73f8ddb \ + --hash=sha256:69079e900bd26b0f65069ac6fa684c74662ed87121c076f2b1cbcf042539034c \ + --hash=sha256:8d7a4a3df943a7c16cd032ccbaab8ed21ff64f4cb090b3a0a15a8b7502ccd876 \ + --hash=sha256:928ed95fefe4e1338d0a7ad2f6b635de59e2ec92adaed4a267f7501a3b252263 \ + --hash=sha256:a79a0885df364b897da44aae308e6ed9cca3a189d455cf1c205bd6f7b03daafa \ + --hash=sha256:ca72e6a4c3c6b8b5605867e16a7f767f5c99b7f526de6bbb903c60eb44fd1e01 \ + --hash=sha256:cd7a5a3a36f975a7678f27849a2d49bafe7272143d938e9b6f3bf28392a3ba00 \ + --hash=sha256:dd2df2ba823e6684230ab4c581f2320be38d7f46de11ce21d2dbba631470d7b6 \ + --hash=sha256:df3cb58b7da91f4fc647d09c3e96006cd6c7bd424a81ce2308a58593c6887c39 \ + --hash=sha256:ed5659cde099f39995f4cb793fd939d2260b4a26e4e29412c91e7537f53d8d25 \ + --hash=sha256:f07e5e0df40a09154007da41b76932671333f9fecb0735c698b19da25aa08927 \ + --hash=sha256:f40c6c6c3a1b398b56d3a8b28f7b455ac1ce4cbb1469f8d35d3bbc804d83daa4 \ + --hash=sha256:f511faf719b797ef0f14688f1abe20b3fd126209cf58512354d1813249745119 \ + --hash=sha256:f806af0ee451a81099c449c4cff0e813056fdf7dd264f3d3a8fd321b17ff9efc # via -r contrib/container/requirements.in -wheel==0.44.0 \ - --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ - --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 +wheel==0.45.1 \ + --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ + --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 # via -r contrib/container/requirements.in diff --git a/contrib/dev_reqs/requirements.txt b/contrib/dev_reqs/requirements.txt index b1f8b7efae..805bbba369 100644 --- a/contrib/dev_reqs/requirements.txt +++ b/contrib/dev_reqs/requirements.txt @@ -1,104 +1,119 @@ # This file was autogenerated by uv via the following command: # uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt --no-strip-extras --generate-hashes -certifi==2024.7.4 \ - --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ - --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 +certifi==2024.8.30 \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 # via requests -charset-normalizer==3.3.2 \ - --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ - --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ - --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ - --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ - --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ - --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ - --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ - --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ - --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ - --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ - --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ - --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ - --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ - --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ - --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ - --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ - --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ - --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ - --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ - --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ - --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ - --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ - --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ - --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ - --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ - --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ - --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ - --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ - --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ - --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ - --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ - --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ - --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ - --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ - --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ - --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ - --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ - --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ - --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ - --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ - --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ - --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ - --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ - --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ - --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ - --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ - --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ - --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ - --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ - --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ - --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ - --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ - --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ - --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ - --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ - --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ - --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ - --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ - --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ - --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ - --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ - --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ - --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ - --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ - --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ - --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ - --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ - --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ - --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ - --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ - --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ - --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ - --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ - --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ - --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ - --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ - --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ - --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ - --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ - --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ - --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ - --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ - --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ - --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ - --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ - --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ - --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ - --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ - --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ - --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 +charset-normalizer==3.4.0 \ + --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ + --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ + --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ + --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ + --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ + --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ + --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ + --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ + --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ + --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ + --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ + --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ + --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ + --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ + --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ + --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ + --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ + --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ + --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ + --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ + --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ + --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ + --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ + --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ + --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ + --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ + --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ + --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ + --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ + --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ + --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ + --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ + --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ + --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ + --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ + --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ + --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ + --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ + --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ + --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ + --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ + --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ + --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ + --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ + --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ + --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ + --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ + --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ + --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ + --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ + --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ + --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ + --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ + --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ + --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ + --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ + --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ + --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ + --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ + --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ + --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ + --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ + --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ + --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ + --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ + --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ + --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ + --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ + --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ + --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ + --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ + --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ + --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ + --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ + --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ + --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ + --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ + --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ + --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ + --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ + --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ + --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ + --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ + --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ + --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ + --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ + --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ + --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ + --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ + --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ + --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ + --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ + --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ + --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ + --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ + --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ + --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ + --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ + --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ + --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ + --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ + --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ + --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ + --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ + --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 # via requests -idna==3.7 \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 +idna==3.10 \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests jc==1.25.3 \ --hash=sha256:ea17a8578497f2da92f73924d9d403f4563ba59422fbceff7bb4a16cdf84a54f \ @@ -171,63 +186,54 @@ ruamel-yaml==0.18.6 \ --hash=sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636 \ --hash=sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b # via jc -ruamel-yaml-clib==0.2.8 \ - --hash=sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d \ - --hash=sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001 \ - --hash=sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462 \ - --hash=sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9 \ - --hash=sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe \ - --hash=sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b \ - --hash=sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b \ - --hash=sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615 \ - --hash=sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62 \ - --hash=sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15 \ - --hash=sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b \ - --hash=sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1 \ - --hash=sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9 \ - --hash=sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675 \ - --hash=sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899 \ - --hash=sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7 \ - --hash=sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7 \ - --hash=sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312 \ - --hash=sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa \ - --hash=sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91 \ - --hash=sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b \ - --hash=sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6 \ - --hash=sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3 \ - --hash=sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334 \ - --hash=sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5 \ - --hash=sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3 \ - --hash=sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe \ - --hash=sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c \ - --hash=sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed \ - --hash=sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337 \ - --hash=sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880 \ - --hash=sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f \ - --hash=sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d \ - --hash=sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248 \ - --hash=sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d \ - --hash=sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf \ - --hash=sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512 \ - --hash=sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069 \ - --hash=sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb \ - --hash=sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942 \ - --hash=sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d \ - --hash=sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31 \ - --hash=sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92 \ - --hash=sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5 \ - --hash=sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28 \ - --hash=sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d \ - --hash=sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1 \ - --hash=sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2 \ - --hash=sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875 \ - --hash=sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412 +ruamel-yaml-clib==0.2.12 \ + --hash=sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b \ + --hash=sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4 \ + --hash=sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef \ + --hash=sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5 \ + --hash=sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632 \ + --hash=sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6 \ + --hash=sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680 \ + --hash=sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf \ + --hash=sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da \ + --hash=sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6 \ + --hash=sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a \ + --hash=sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519 \ + --hash=sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6 \ + --hash=sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f \ + --hash=sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd \ + --hash=sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2 \ + --hash=sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52 \ + --hash=sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd \ + --hash=sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d \ + --hash=sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c \ + --hash=sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6 \ + --hash=sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb \ + --hash=sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969 \ + --hash=sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28 \ + --hash=sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e \ + --hash=sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45 \ + --hash=sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4 \ + --hash=sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12 \ + --hash=sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31 \ + --hash=sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642 \ + --hash=sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e \ + --hash=sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285 \ + --hash=sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed \ + --hash=sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1 \ + --hash=sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7 \ + --hash=sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3 \ + --hash=sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475 \ + --hash=sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5 \ + --hash=sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76 \ + --hash=sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987 \ + --hash=sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df # via ruamel-yaml -urllib3==2.2.2 \ - --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ - --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 +urllib3==2.2.3 \ + --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ + --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 # via requests -xmltodict==0.13.0 \ - --hash=sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56 \ - --hash=sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852 +xmltodict==0.14.2 \ + --hash=sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553 \ + --hash=sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac # via jc diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index df82fc361e..f62cf923b4 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,13 +1,16 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 284 +INVENTREE_API_VERSION = 285 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v285 - 2024-11-25 : https://github.com/inventree/InvenTree/pull/8559 + - Adds better description for registration endpoints + v284 - 2024-11-25 : https://github.com/inventree/InvenTree/pull/8544 - Adds new date filters to the StockItem API - Adds new date filters to the BuildOrder API diff --git a/src/backend/requirements-dev.txt b/src/backend/requirements-dev.txt index eb26cd6100..e0f5268cf8 100644 --- a/src/backend/requirements-dev.txt +++ b/src/backend/requirements-dev.txt @@ -198,98 +198,98 @@ click==8.1.7 \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de # via pip-tools -coverage[toml]==7.6.4 \ - --hash=sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376 \ - --hash=sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9 \ - --hash=sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111 \ - --hash=sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172 \ - --hash=sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491 \ - --hash=sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546 \ - --hash=sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2 \ - --hash=sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11 \ - --hash=sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08 \ - --hash=sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c \ - --hash=sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2 \ - --hash=sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963 \ - --hash=sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613 \ - --hash=sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0 \ - --hash=sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db \ - --hash=sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf \ - --hash=sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73 \ - --hash=sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117 \ - --hash=sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1 \ - --hash=sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e \ - --hash=sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522 \ - --hash=sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25 \ - --hash=sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc \ - --hash=sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea \ - --hash=sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52 \ - --hash=sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a \ - --hash=sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07 \ - --hash=sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06 \ - --hash=sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa \ - --hash=sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901 \ - --hash=sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b \ - --hash=sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17 \ - --hash=sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0 \ - --hash=sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21 \ - --hash=sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19 \ - --hash=sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5 \ - --hash=sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51 \ - --hash=sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3 \ - --hash=sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3 \ - --hash=sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f \ - --hash=sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076 \ - --hash=sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a \ - --hash=sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718 \ - --hash=sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba \ - --hash=sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e \ - --hash=sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27 \ - --hash=sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e \ - --hash=sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09 \ - --hash=sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e \ - --hash=sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70 \ - --hash=sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f \ - --hash=sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72 \ - --hash=sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a \ - --hash=sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef \ - --hash=sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b \ - --hash=sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b \ - --hash=sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f \ - --hash=sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806 \ - --hash=sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b \ - --hash=sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1 \ - --hash=sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c \ - --hash=sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858 +coverage[toml]==7.6.8 \ + --hash=sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5 \ + --hash=sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf \ + --hash=sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb \ + --hash=sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638 \ + --hash=sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4 \ + --hash=sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc \ + --hash=sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed \ + --hash=sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a \ + --hash=sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d \ + --hash=sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649 \ + --hash=sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c \ + --hash=sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b \ + --hash=sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4 \ + --hash=sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443 \ + --hash=sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83 \ + --hash=sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee \ + --hash=sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e \ + --hash=sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e \ + --hash=sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3 \ + --hash=sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0 \ + --hash=sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb \ + --hash=sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076 \ + --hash=sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb \ + --hash=sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787 \ + --hash=sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1 \ + --hash=sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e \ + --hash=sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce \ + --hash=sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801 \ + --hash=sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764 \ + --hash=sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365 \ + --hash=sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf \ + --hash=sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6 \ + --hash=sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71 \ + --hash=sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002 \ + --hash=sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4 \ + --hash=sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c \ + --hash=sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8 \ + --hash=sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4 \ + --hash=sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146 \ + --hash=sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc \ + --hash=sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea \ + --hash=sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4 \ + --hash=sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad \ + --hash=sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28 \ + --hash=sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451 \ + --hash=sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50 \ + --hash=sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779 \ + --hash=sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63 \ + --hash=sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e \ + --hash=sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc \ + --hash=sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022 \ + --hash=sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d \ + --hash=sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94 \ + --hash=sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b \ + --hash=sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d \ + --hash=sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331 \ + --hash=sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a \ + --hash=sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0 \ + --hash=sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee \ + --hash=sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92 \ + --hash=sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a \ + --hash=sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9 # via -r src/backend/requirements-dev.in -cryptography==43.0.1 \ - --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ - --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ - --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ - --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ - --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ - --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ - --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ - --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ - --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ - --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ - --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ - --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ - --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ - --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ - --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ - --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ - --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ - --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ - --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ - --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ - --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ - --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ - --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ - --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ - --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ - --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ - --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 +cryptography==43.0.3 \ + --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ + --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ + --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ + --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ + --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ + --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ + --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ + --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ + --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ + --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ + --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ + --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ + --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ + --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ + --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ + --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ + --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ + --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ + --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ + --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ + --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ + --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ + --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ + --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ + --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ + --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ + --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 # via # -c src/backend/requirements.txt # pdfminer-six @@ -322,13 +322,13 @@ filelock==3.16.1 \ --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 # via virtualenv -identify==2.6.1 \ - --hash=sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0 \ - --hash=sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98 +identify==2.6.2 \ + --hash=sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3 \ + --hash=sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd # via pre-commit -importlib-metadata==8.4.0 \ - --hash=sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1 \ - --hash=sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5 +importlib-metadata==8.5.0 \ + --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ + --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 # via # -c src/backend/requirements.txt # build @@ -340,9 +340,9 @@ nodeenv==1.9.1 \ --hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \ --hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9 # via pre-commit -packaging==24.1 \ - --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ - --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 +packaging==24.2 \ + --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ + --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f # via # -c src/backend/requirements.txt # build @@ -350,9 +350,9 @@ pdfminer-six==20240706 \ --hash=sha256:c631a46d5da957a9ffe4460c5dce21e8431dabb615fee5f9f4400603a58d95a6 \ --hash=sha256:f4f70e74174b4b3542fcb8406a210b6e2e27cd0f0b5fd04534a8cc0d8951e38c # via -r src/backend/requirements-dev.in -pip==24.2 \ - --hash=sha256:2cd581cf58ab7fcfca4ce8efa6dcacd0de5bf8d0a3eb9ec927e07405f4d9e2a2 \ - --hash=sha256:5b5e490b5e9cb275c879595064adce9ebd31b854e3e803740b72f9ccf34a45b8 +pip==24.3.1 \ + --hash=sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed \ + --hash=sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99 # via pip-tools pip-tools==7.4.1 \ --hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \ @@ -361,7 +361,9 @@ pip-tools==7.4.1 \ platformdirs==4.3.6 \ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb - # via virtualenv + # via + # -c src/backend/requirements.txt + # virtualenv pre-commit==4.0.1 \ --hash=sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2 \ --hash=sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878 @@ -435,22 +437,22 @@ pyyaml==6.0.2 \ # via # -c src/backend/requirements.txt # pre-commit -setuptools==75.1.0 \ - --hash=sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2 \ - --hash=sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538 +setuptools==75.6.0 \ + --hash=sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6 \ + --hash=sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d # via # -c src/backend/requirements.txt # -r src/backend/requirements-dev.in # pip-tools -sqlparse==0.5.1 \ - --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ - --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e +sqlparse==0.5.2 \ + --hash=sha256:9e37b35e16d1cc652a2545f0997c1deb23ea28fa1f3eefe609eee3063c3b105f \ + --hash=sha256:e99bc85c78160918c3e1d9230834ab8d80fc06c59d03f8db2618f65f65dda55e # via # -c src/backend/requirements.txt # django -tomli==2.0.2 \ - --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ - --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed +tomli==2.1.0 \ + --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ + --hash=sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391 # via # -c src/backend/requirements.txt # build @@ -463,17 +465,17 @@ typing-extensions==4.12.2 \ # -c src/backend/requirements.txt # asgiref # django-test-migrations -virtualenv==20.27.0 \ - --hash=sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2 \ - --hash=sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655 +virtualenv==20.27.1 \ + --hash=sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba \ + --hash=sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4 # via pre-commit -wheel==0.44.0 \ - --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ - --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 +wheel==0.45.1 \ + --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ + --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 # via pip-tools -zipp==3.20.2 \ - --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ - --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 +zipp==3.21.0 \ + --hash=sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4 \ + --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931 # via # -c src/backend/requirements.txt # importlib-metadata diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt index db384d0b02..6794b927c5 100644 --- a/src/backend/requirements.txt +++ b/src/backend/requirements.txt @@ -1,19 +1,16 @@ # This file was autogenerated by uv via the following command: # uv pip compile src/backend/requirements.in -o src/backend/requirements.txt --no-strip-extras --generate-hashes -appdirs==1.4.4 \ - --hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \ - --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 - # via pint asgiref==3.8.1 \ --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \ --hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590 # via # django + # django-allauth # django-cors-headers # django-structlog -async-timeout==4.0.3 \ - --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ - --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 +async-timeout==5.0.1 \ + --hash=sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c \ + --hash=sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3 # via redis attrs==24.2.0 \ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ @@ -25,14 +22,15 @@ babel==2.16.0 \ --hash=sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b \ --hash=sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316 # via py-moneyed -bleach[css]==6.1.0 \ - --hash=sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe \ - --hash=sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6 +bleach[css]==6.2.0 \ + --hash=sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e \ + --hash=sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f # via django-markdownify brotli==1.1.0 \ --hash=sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208 \ --hash=sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48 \ --hash=sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354 \ + --hash=sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419 \ --hash=sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a \ --hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \ --hash=sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c \ @@ -40,43 +38,67 @@ brotli==1.1.0 \ --hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \ --hash=sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a \ --hash=sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3 \ + --hash=sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757 \ + --hash=sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2 \ --hash=sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438 \ --hash=sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578 \ --hash=sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b \ --hash=sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b \ --hash=sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68 \ + --hash=sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0 \ --hash=sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d \ + --hash=sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943 \ --hash=sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd \ --hash=sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409 \ + --hash=sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28 \ --hash=sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da \ --hash=sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50 \ + --hash=sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f \ --hash=sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0 \ + --hash=sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547 \ --hash=sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180 \ + --hash=sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0 \ --hash=sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d \ + --hash=sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a \ + --hash=sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb \ --hash=sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112 \ --hash=sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc \ + --hash=sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2 \ --hash=sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265 \ --hash=sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327 \ --hash=sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95 \ + --hash=sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec \ --hash=sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd \ + --hash=sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c \ + --hash=sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38 \ --hash=sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914 \ --hash=sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0 \ --hash=sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a \ --hash=sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7 \ + --hash=sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368 \ + --hash=sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c \ --hash=sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0 \ + --hash=sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f \ --hash=sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451 \ --hash=sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f \ + --hash=sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8 \ --hash=sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e \ --hash=sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248 \ + --hash=sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c \ --hash=sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91 \ --hash=sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724 \ + --hash=sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7 \ --hash=sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966 \ + --hash=sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9 \ --hash=sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97 \ --hash=sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d \ + --hash=sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5 \ --hash=sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf \ --hash=sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac \ + --hash=sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b \ --hash=sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951 \ --hash=sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74 \ + --hash=sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648 \ --hash=sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60 \ --hash=sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c \ --hash=sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1 \ @@ -87,27 +109,44 @@ brotli==1.1.0 \ --hash=sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460 \ --hash=sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751 \ --hash=sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9 \ + --hash=sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2 \ + --hash=sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0 \ --hash=sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1 \ --hash=sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474 \ + --hash=sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75 \ + --hash=sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5 \ + --hash=sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f \ --hash=sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2 \ + --hash=sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f \ + --hash=sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb \ --hash=sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6 \ --hash=sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9 \ + --hash=sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111 \ --hash=sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2 \ + --hash=sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01 \ --hash=sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467 \ --hash=sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619 \ --hash=sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf \ --hash=sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408 \ --hash=sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579 \ --hash=sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84 \ + --hash=sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7 \ + --hash=sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c \ + --hash=sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284 \ + --hash=sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52 \ --hash=sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b \ --hash=sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59 \ --hash=sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752 \ + --hash=sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1 \ --hash=sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80 \ + --hash=sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839 \ --hash=sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0 \ --hash=sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2 \ --hash=sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3 \ --hash=sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64 \ + --hash=sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089 \ --hash=sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643 \ + --hash=sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b \ --hash=sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e \ --hash=sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985 \ --hash=sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596 \ @@ -306,34 +345,34 @@ coreschema==0.0.4 \ --hash=sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f \ --hash=sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607 # via coreapi -cryptography==43.0.1 \ - --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ - --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ - --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ - --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ - --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ - --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ - --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ - --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ - --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ - --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ - --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ - --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ - --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ - --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ - --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ - --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ - --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ - --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ - --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ - --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ - --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ - --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ - --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ - --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ - --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ - --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ - --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 +cryptography==43.0.3 \ + --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ + --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ + --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ + --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ + --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ + --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ + --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ + --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ + --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ + --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ + --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ + --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ + --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ + --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ + --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ + --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ + --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ + --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ + --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ + --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ + --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ + --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ + --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ + --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ + --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ + --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ + --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 # via # -r src/backend/requirements.in # djangorestframework-simplejwt @@ -347,20 +386,20 @@ defusedxml==0.7.1 \ # via # odfpy # python3-openid -deprecated==1.2.14 \ - --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ - --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 +deprecated==1.2.15 \ + --hash=sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320 \ + --hash=sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d # via # opentelemetry-api # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http # opentelemetry-semantic-conventions -diff-match-patch==20230430 \ - --hash=sha256:953019cdb9c9d2c9e47b5b12bcff3cf4746fc4598eb406076fa1fc27e6a1f15c \ - --hash=sha256:dce43505fb7b1b317de7195579388df0746d90db07015ed47a85e5e44930ef93 +diff-match-patch==20241021 \ + --hash=sha256:93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782 \ + --hash=sha256:beae57a99fa48084532935ee2968b8661db861862ec82c6f21f4acdd6d835073 # via django-import-export -dj-rest-auth==6.0.0 \ - --hash=sha256:760b45f3a07cd6182e6a20fe07d0c55230c5f950167df724d7914d0dd8c50133 +dj-rest-auth==7.0.0 \ + --hash=sha256:08dbc03a35223872da9f59bc2d7a71bec2e721aa69f7cdc84c7a329aeae1f86e # via -r src/backend/requirements.in django==4.2.16 \ --hash=sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898 \ @@ -398,8 +437,8 @@ django==4.2.16 \ # djangorestframework # djangorestframework-simplejwt # drf-spectacular -django-allauth[openid, saml]==64.1.0 \ - --hash=sha256:713bfc410021140aefae0f04eeaac5d50ebedad7abaf43174670a9ec002c595c +django-allauth[openid, saml]==65.2.0 \ + --hash=sha256:0a3d7baf7beefd6fe8027316302c26ece7433cf4331a3b245d15fc9a7be68b6f # via # -r src/backend/requirements.in # django-allauth-2fa @@ -411,9 +450,9 @@ django-cleanup==9.0.0 \ --hash=sha256:19f8b0e830233f9f0f683b17181f414672a0f48afe3ea3cc80ba47ae40ad880c \ --hash=sha256:bb9fb560aaf62959c81e31fa40885c36bbd5854d5aa21b90df2c7e4ba633531e # via -r src/backend/requirements.in -django-cors-headers==4.5.0 \ - --hash=sha256:28c1ded847aa70208798de3e42422a782f427b8b720e8d7319d34b654b5978e6 \ - --hash=sha256:6c01a85cf1ec779a7bde621db853aa3ce5c065a5ba8e27df7a9f9e8dac310f4f +django-cors-headers==4.6.0 \ + --hash=sha256:14d76b4b4c8d39375baeddd89e4f08899051eeaf177cb02a29bd6eae8cf63aa8 \ + --hash=sha256:8edbc0497e611c24d5150e0055d3b178c6534b8ed826fb6f53b21c63f5d48ba3 # via -r src/backend/requirements.in django-crispy-forms==1.14.0 \ --hash=sha256:35887b8851a931374dd697207a8f56c57a9c5cb9dbf0b9fa54314da5666cea5b \ @@ -482,9 +521,9 @@ django-picklefield==3.2 \ django-q-sentry==0.1.6 \ --hash=sha256:9b8b4d7fad253a7d9a47f2c2ab0d9dea83078b7ef45c8849dbb1e4176ef8d050 # via -r src/backend/requirements.in -django-q2==1.7.3 \ - --hash=sha256:949e85fdc0aae9820bf9c10dc31e31cb05b21e8b919bf294221aa41c37030e25 \ - --hash=sha256:96bacc384683617823077e20c9007ad7cdc35a6d4c1671b9589e6e28cf93ff4c +django-q2==1.7.4 \ + --hash=sha256:56a3781cc480474fa9c04bbde62445b0a9b4195adc409bd963b8f593b0598c43 \ + --hash=sha256:6eda6d56505822ee5ebc6c4eac1dde726f5dbf20ee9ea7080575535852e2671f # via -r src/backend/requirements.in django-recurrence==1.11.1 \ --hash=sha256:0c65f30872599b5813a9bab6952dada23c55894f28674490a753ada559f14bc5 \ @@ -544,58 +583,53 @@ drf-spectacular==0.27.2 \ --hash=sha256:a199492f2163c4101055075ebdbb037d59c6e0030692fc83a1a8c0fc65929981 \ --hash=sha256:b1c04bf8b2fbbeaf6f59414b4ea448c8787aba4d32f76055c3b13335cf7ec37b # via -r src/backend/requirements.in -dulwich==0.22.1 \ - --hash=sha256:0d72a88c7af8fafa14c8743e8923c8d46bd0b850a0b7f5e34eb49201f1ead88e \ - --hash=sha256:0ea4c5feedd35e8bde175a9ab91ef6705c3cef5ee209eeb2f67dd0b59ff1825f \ - --hash=sha256:12482e318895da9acabea7c0cc70b35d36833e7cb2def511ab3a63617f5c1af3 \ - --hash=sha256:155124219e6ce4b116d30ed1b9cc63c88021966b29ce761d3ce3caba064f9a13 \ - --hash=sha256:1bc6575476539c0b4924abab3896fc76be2f413d5baa6b083c4dfc4abc59329e \ - --hash=sha256:20f61f6dc0b075ca6459acbfb9527ee0e1ee02dccbed126dc492600bb7310d86 \ - --hash=sha256:3a366cdba24b8df31ad70b82bae55baa696c453678c1346da8390396a1d5cce4 \ - --hash=sha256:3ad3462d070b678fe61d3bdd7c6ac3fdbd25cca66f32b6edf589dd88fff251d2 \ - --hash=sha256:3ae006498fea11515027a417e6e68b82e1c195d3516188ba2cc08210e3022d14 \ - --hash=sha256:3de7a2eba26ff13a79670f78f73fc86fb8c87100508119f3b6bd61451bfdd4bf \ - --hash=sha256:3fb61891b2675664dc89d486eb5199e3659179ae04fc0a863ffc7e16b782b624 \ - --hash=sha256:41dfc52db29a06fe23a5029abc3bc13503e28233b1c3a9614bc1e5c4d6adc1ce \ - --hash=sha256:454d073e628043dde4f9bd34517736c1889dbe6417099bbae2119873b8d4d5da \ - --hash=sha256:467ff87fc4c61a23424b32acd952476ba17e7f7eeb8090e5957f68129784a35f \ - --hash=sha256:4c509e8172b9438536946097768413f297229b03eff064e4e06749cf5c28df78 \ - --hash=sha256:524d3497a86f79959c9c1d729715d60d8171ed3f71621d45afb4faee5a47e8a1 \ - --hash=sha256:52a8ddd1d9b5681de216a7af718720f5202d3c093ecc10dd4dfac6d25da605a6 \ - --hash=sha256:5e36c8a3bb09db5730b3d5014d087bce977e878825cdd7ba8285abcd81c43bc0 \ - --hash=sha256:6386165c64ba5f61c416301f7f32bb899f8200ca575d76888697a42fda8a92d2 \ - --hash=sha256:64eebe1d709539d6e80440fa1185f1eeb260d53bcb6435b1f753b4ce90a65e82 \ - --hash=sha256:6dc42afedc8cda4f2fd15a06d2e9e41281074a02cdf31bb2e0dde4d80766a408 \ - --hash=sha256:7244b796dd7e191753b822ac0ca871a4b9139b0b850770ac5bd347d5f8c76768 \ - --hash=sha256:739ef91aeb13fa2aa187d0efd46d0ac168301f54a6ef748565c42876b4b3ce71 \ - --hash=sha256:7579429e89deac6659b4ea70eb3de9063bb40508fd4a8a020fa67b02e0b59f4f \ - --hash=sha256:82f26e592e9a36ab33bcdb419c7d53320e26c85dfc254cdb84f5f561a2fcaabf \ - --hash=sha256:84db8aef08df6431b017cc3abe57b3d6885fd7436eec8d715603c309353b233c \ - --hash=sha256:86be1e283d78cc3f7daee1dcd0254122160cde71ca8c5348315156045f8ac2bb \ - --hash=sha256:892914dc2e80403d16e59a3b440044f6092fde5ffd4ec1fdf36d6ff20a8e624d \ - --hash=sha256:91966b7b48ec939e5083b03c9154fc450508056f01650ecb58724095307427f5 \ - --hash=sha256:926d671654a2f8cfa0b2fcb6b0c46833af95b5265d27a5c56c49c5a10f3ff3ba \ - --hash=sha256:9d19f04ecd4628a0e4587b4c4e98e040b87924c1362ae5aa27420435f05d5dd8 \ - --hash=sha256:a18d1392eabd02f337dcba23d723a4dcca87274ce8693cf88e6320f38bc3fdcd \ - --hash=sha256:a2c790517ed884bc1b1590806222ab44989eeb7e7f14dfa915561c7ee3b9ac73 \ - --hash=sha256:ac9fcf7c5cf1e9d0bcc643672f81bf43ec81f6495b99809649f5bfcdff633ab0 \ - --hash=sha256:b03092399f0f5d3e112405b890128afdb9e1f203eafb812f5d9105b0f5fac9d4 \ - --hash=sha256:b069639757b2f287f9cd0daf6765b536558c5e28263bbbb28e3d1925bce75400 \ - --hash=sha256:b2054e1f2c7041857ce129443bde23298ca37592ce82f0fb5ed5704d5f3708dd \ - --hash=sha256:b2c3186cf76d598a9d42b35e09ef35d499118b4197624ba5bba1b3a39ac6a75f \ - --hash=sha256:d3146843b972f744aed551e8ac9fac5714baa864393e480586d467b7b4488426 \ - --hash=sha256:e1b51d26108a832f151da8856a93676cc1a5cd8dd0bc20f06f4aee5774a7f0f9 \ - --hash=sha256:e346c1b86c5e5f175ca8f87f3873eea8b2e0eeb5d52033b475cf85641cb200c2 \ - --hash=sha256:e36d85967cfbf25da1c7bc3d6921adc5baa976969d926aaf1582bd5fd7e94758 \ - --hash=sha256:e3c7774232a2c9b195bde4fb72ad71455e877a9e4e9c0b17a57b1d9bd478838c \ - --hash=sha256:e7798e842ec506d25f21e825259b70109325ac1c9b43c2e287aad7559455951b \ - --hash=sha256:e90b8a2f24149c5803b733a24f1a016a2943b1f5a9ab2360db545e4638354c35 \ - --hash=sha256:f9e10678fe0692c5167553981d97cbe342ed055c49016aef10da336e2962b1f2 \ - --hash=sha256:fd51e77ff1b4ca08bc9b09b85646a3e77f275827b7b30180d76d769ce608e64d +dulwich==0.22.6 \ + --hash=sha256:06b4fde8d173578a56602dd79b42d5a9121e323ebb8a68102c26a44ce2dd14dc \ + --hash=sha256:096a9fe8754bce136e128b7161fca30ff1b2e5859f2324a7e2c8270dcb2ba672 \ + --hash=sha256:0fca415dc613434a371e9058e1e7f2a1331361a23e41ebae9442b903f553bc3b \ + --hash=sha256:115920aff5756cdf02900504fe3c9b941f2f41fab5cea2670130783f02e0ae2c \ + --hash=sha256:1b883cd35f755491f79b89c70f082e9e6232361a0281642594f4a2bf8051a7dd \ + --hash=sha256:1e61b8993d5d5c63682215f67104fc75dcfd9927e214df2be5baff333bafd69a \ + --hash=sha256:1f0040aa840c9632b973bd98484e584bb21690738c2be1ebd23b0c5af3214b2f \ + --hash=sha256:2085f13dc7a0d7cae06c7fb04b06d3b2f6205029d44c41b65d37a23da0cb67cb \ + --hash=sha256:25dd3c7217887621cd2d1703329a1e00338bb8839d54137b63e44a6a2d226603 \ + --hash=sha256:308446a339dcda7498a4ed2748f36ecf0e4849875df573613243ac845f781771 \ + --hash=sha256:3722b8f09aef30bd30e64a7e4589eba042e530b407d98409350b629da10dd54f \ + --hash=sha256:40951f82c80561030175e73f09845f24ebbee88dfd76abda8e4d58d756b95c65 \ + --hash=sha256:43abc96dabbe79117df3862b35694a52aa0afbe4d68d3e83bcff55ac71c851cb \ + --hash=sha256:48e4262bfa68635a97bbe0c2ce4f4092ef903a7f3127b61b8ed634ef2538fdc8 \ + --hash=sha256:4915476feacaeb7e8975942d93d69bf9baf2e87c2a9eab779864aa7319616563 \ + --hash=sha256:4b84f9a849d64201a8e5cde024bbbf9c56d3138f284eb5cc1a937ee3503f18b0 \ + --hash=sha256:502cc8ffe2d4f2e7bd347549e8bd1d31a8408dd990f5df2b028853229027baae \ + --hash=sha256:58c91a6409e761f8dd9fd68f28163bcb00bb7a21eebb52655a2adcaf8ee53447 \ + --hash=sha256:6290edb86155b350a3504582570891b0a7593766d91d6b89cdd24d01061f019f \ + --hash=sha256:6fda801469f3cbd982898f224696adb4afd72f2f42bbbbfe1ded2632b3a85dba \ + --hash=sha256:737284cbf4a3de239b1962e5ec2cacf0506d2d0a857b82e9fd2b4a08b913c11e \ + --hash=sha256:75e0c2ad0eb809eda2c1c1253768632e421b099245c12ffddf8a6f109c2fe32e \ + --hash=sha256:82039b537ef31dceb04e513f9bc1571e05d283c242fa0aa2c7484ff9dc2ca1ae \ + --hash=sha256:84ac8d08cbadfb8972de597ab4c0286119409449c7bed207a02f7d62bb5c5b4b \ + --hash=sha256:8c8711a00f45d923f8febc047866fa7e845ea19bcdb930f48ddc2a121d1ed8bd \ + --hash=sha256:a609c1939b8050c9876d0dd2b15302fef695759f479613c20025fbd4ece32bda \ + --hash=sha256:b18bdf05ed09288b9d8dbbf927a2c3a63fa6192eced25665514959dea92a389b \ + --hash=sha256:b1a08ad0c6ae572142b7775f6fe028e0e3ac9c01a295344c41049e257c5af980 \ + --hash=sha256:c1f44d599fa5dc59ca43e0789f835b8689b4d831d8de5ae009c442192a1408b5 \ + --hash=sha256:cc0810d6e65787ba0f41eb0dbe3e39520d85fd409d8a0e9a15d48cb194b77c6f \ + --hash=sha256:d6684297967833961c81333cbf105b0c2cd3f1a824873b85d60d265ec751fe57 \ + --hash=sha256:db10da1719575b5b113e006b8fc9ed7bbf4fd5488db242e85dcea2191c0d4b99 \ + --hash=sha256:dd8303b570fd439e0facbb7476a658fe865bc985eab04e9a18b7ffc0f5d56d49 \ + --hash=sha256:de9fccefd61b5098ff755453975021035a8d385896edb57163050251c30ea3b6 \ + --hash=sha256:dff11fe1ecd6f9d915b490c660456a467c9150404de5100b3cf112c6bd5c830d \ + --hash=sha256:e05edb22519b39f8396e5d36e23e08485d992f04d6acfdd7f4cff2ca3ba5b8c7 \ + --hash=sha256:eb5f8ff0eb0d6759cebd13cb9e6d7029af5d87f89074bd1a702c7a0943a33d6e \ + --hash=sha256:eb662463f205f106776af499d054c98f408c3753a6c0eaff8612eb3f1cbf6ddb \ + --hash=sha256:ec5d376f7f02651301b58e04888bd5d671577fc68cc7dada23793907119c22bd \ + --hash=sha256:f9e75774fe5f219490912931bb8d91a12ec5cc7155f377fd88088fe0f035e1b8 \ + --hash=sha256:fcf1894ac54023266a0cda78d3c997c56328164bdfcd300aab8201e8bcb7decd \ + --hash=sha256:ffa95d2d903f387f1a5206adb3d832013803a49e9b04c8749dd369f308f66824 # via -r src/backend/requirements.in -et-xmlfile==1.1.0 \ - --hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \ - --hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada +et-xmlfile==2.0.0 \ + --hash=sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa \ + --hash=sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54 # via openpyxl feedparser==6.0.11 \ --hash=sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45 \ @@ -605,122 +639,124 @@ flexcache==0.3 \ --hash=sha256:18743bd5a0621bfe2cf8d519e4c3bfdf57a269c15d1ced3fb4b64e0ff4600656 \ --hash=sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32 # via pint -flexparser==0.3.1 \ - --hash=sha256:2e3e2936bec1f9277f777ef77297522087d96adb09624d4fe4240fd56885c013 \ - --hash=sha256:36f795d82e50f5c9ae2fde1c33f21f88922fdd67b7629550a3cc4d0b40a66856 +flexparser==0.4 \ + --hash=sha256:266d98905595be2ccc5da964fe0a2c3526fbbffdc45b65b3146d75db992ef6b2 \ + --hash=sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846 # via pint -fonttools[woff]==4.54.1 \ - --hash=sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6 \ - --hash=sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263 \ - --hash=sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1 \ - --hash=sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e \ - --hash=sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556 \ - --hash=sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d \ - --hash=sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e \ - --hash=sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2 \ - --hash=sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986 \ - --hash=sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb \ - --hash=sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd \ - --hash=sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882 \ - --hash=sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44 \ - --hash=sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac \ - --hash=sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20 \ - --hash=sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d \ - --hash=sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a \ - --hash=sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c \ - --hash=sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d \ - --hash=sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff \ - --hash=sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7 \ - --hash=sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10 \ - --hash=sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02 \ - --hash=sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2 \ - --hash=sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07 \ - --hash=sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b \ - --hash=sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08 \ - --hash=sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab \ - --hash=sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285 \ - --hash=sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c \ - --hash=sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58 \ - --hash=sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9 \ - --hash=sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc \ - --hash=sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab \ - --hash=sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55 \ - --hash=sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714 \ - --hash=sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8 \ - --hash=sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33 \ - --hash=sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d \ - --hash=sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e \ - --hash=sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664 \ - --hash=sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7 \ - --hash=sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a \ - --hash=sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b \ - --hash=sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13 \ - --hash=sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a \ - --hash=sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386 \ - --hash=sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac +fonttools[woff]==4.55.0 \ + --hash=sha256:00f7cf55ad58a57ba421b6a40945b85ac7cc73094fb4949c41171d3619a3a47e \ + --hash=sha256:01124f2ca6c29fad4132d930da69158d3f49b2350e4a779e1efbe0e82bd63f6c \ + --hash=sha256:12db5888cd4dd3fcc9f0ee60c6edd3c7e1fd44b7dd0f31381ea03df68f8a153f \ + --hash=sha256:161d1ac54c73d82a3cded44202d0218ab007fde8cf194a23d3dd83f7177a2f03 \ + --hash=sha256:1f0e115281a32ff532118aa851ef497a1b7cda617f4621c1cdf81ace3e36fb0c \ + --hash=sha256:23bbbb49bec613a32ed1b43df0f2b172313cee690c2509f1af8fdedcf0a17438 \ + --hash=sha256:2863555ba90b573e4201feaf87a7e71ca3b97c05aa4d63548a4b69ea16c9e998 \ + --hash=sha256:2b3ab90ec0f7b76c983950ac601b58949f47aca14c3f21eed858b38d7ec42b05 \ + --hash=sha256:31d00f9852a6051dac23294a4cf2df80ced85d1d173a61ba90a3d8f5abc63c60 \ + --hash=sha256:33b52a9cfe4e658e21b1f669f7309b4067910321757fec53802ca8f6eae96a5a \ + --hash=sha256:37dbb3fdc2ef7302d3199fb12468481cbebaee849e4b04bc55b77c24e3c49189 \ + --hash=sha256:3e569711464f777a5d4ef522e781dc33f8095ab5efd7548958b36079a9f2f88c \ + --hash=sha256:3f901cef813f7c318b77d1c5c14cf7403bae5cb977cede023e22ba4316f0a8f6 \ + --hash=sha256:51c029d4c0608a21a3d3d169dfc3fb776fde38f00b35ca11fdab63ba10a16f61 \ + --hash=sha256:5435e5f1eb893c35c2bc2b9cd3c9596b0fcb0a59e7a14121562986dd4c47b8dd \ + --hash=sha256:553bd4f8cc327f310c20158e345e8174c8eed49937fb047a8bda51daf2c353c8 \ + --hash=sha256:55718e8071be35dff098976bc249fc243b58efa263768c611be17fe55975d40a \ + --hash=sha256:61dc0a13451143c5e987dec5254d9d428f3c2789a549a7cf4f815b63b310c1cc \ + --hash=sha256:636caaeefe586d7c84b5ee0734c1a5ab2dae619dc21c5cf336f304ddb8f6001b \ + --hash=sha256:6c99b5205844f48a05cb58d4a8110a44d3038c67ed1d79eb733c4953c628b0f6 \ + --hash=sha256:7208856f61770895e79732e1dcbe49d77bd5783adf73ae35f87fcc267df9db81 \ + --hash=sha256:732a9a63d6ea4a81b1b25a1f2e5e143761b40c2e1b79bb2b68e4893f45139a40 \ + --hash=sha256:7636acc6ab733572d5e7eec922b254ead611f1cdad17be3f0be7418e8bfaca71 \ + --hash=sha256:7dd91ac3fcb4c491bb4763b820bcab6c41c784111c24172616f02f4bc227c17d \ + --hash=sha256:8118dc571921dc9e4b288d9cb423ceaf886d195a2e5329cc427df82bba872cd9 \ + --hash=sha256:81ffd58d2691f11f7c8438796e9f21c374828805d33e83ff4b76e4635633674c \ + --hash=sha256:838d2d8870f84fc785528a692e724f2379d5abd3fc9dad4d32f91cf99b41e4a7 \ + --hash=sha256:8c9679fc0dd7e8a5351d321d8d29a498255e69387590a86b596a45659a39eb0d \ + --hash=sha256:9ce4ba6981e10f7e0ccff6348e9775ce25ffadbee70c9fd1a3737e3e9f5fa74f \ + --hash=sha256:a656652e1f5d55b9728937a7e7d509b73d23109cddd4e89ee4f49bde03b736c6 \ + --hash=sha256:a7ad1f1b98ab6cb927ab924a38a8649f1ffd7525c75fe5b594f5dab17af70e18 \ + --hash=sha256:aa046f6a63bb2ad521004b2769095d4c9480c02c1efa7d7796b37826508980b6 \ + --hash=sha256:abe62987c37630dca69a104266277216de1023cf570c1643bb3a19a9509e7a1b \ + --hash=sha256:b2e526b325a903868c62155a6a7e24df53f6ce4c5c3160214d8fe1be2c41b478 \ + --hash=sha256:b5263d8e7ef3c0ae87fbce7f3ec2f546dc898d44a337e95695af2cd5ea21a967 \ + --hash=sha256:b7ef9068a1297714e6fefe5932c33b058aa1d45a2b8be32a4c6dee602ae22b5c \ + --hash=sha256:bca35b4e411362feab28e576ea10f11268b1aeed883b9f22ed05675b1e06ac69 \ + --hash=sha256:ca7fd6987c68414fece41c96836e945e1f320cda56fc96ffdc16e54a44ec57a2 \ + --hash=sha256:d12081729280c39d001edd0f4f06d696014c26e6e9a0a55488fabc37c28945e4 \ + --hash=sha256:dd2820a8b632f3307ebb0bf57948511c2208e34a4939cf978333bc0a3f11f838 \ + --hash=sha256:e198e494ca6e11f254bac37a680473a311a88cd40e58f9cc4dc4911dfb686ec6 \ + --hash=sha256:e7e6a352ff9e46e8ef8a3b1fe2c4478f8a553e1b5a479f2e899f9dc5f2055880 \ + --hash=sha256:e8e67974326af6a8879dc2a4ec63ab2910a1c1a9680ccd63e4a690950fceddbe \ + --hash=sha256:f0a4b52238e7b54f998d6a56b46a2c56b59c74d4f8a6747fb9d4042190f37cd3 \ + --hash=sha256:f27526042efd6f67bfb0cc2f1610fa20364396f8b1fc5edb9f45bb815fb090b2 \ + --hash=sha256:f307f6b5bf9e86891213b293e538d292cd1677e06d9faaa4bf9c086ad5f132f6 \ + --hash=sha256:f46b863d74bab7bb0d395f3b68d3f52a03444964e67ce5c43ce43a75efce9246 \ + --hash=sha256:f50a1f455902208486fbca47ce33054208a4e437b38da49d6721ce2fef732fcf \ + --hash=sha256:f8c8c76037d05652510ae45be1cd8fb5dd2fd9afec92a25374ac82255993d57c \ + --hash=sha256:fa34aa175c91477485c44ddfbb51827d470011e558dfd5c7309eb31bef19ec51 # via weasyprint -googleapis-common-protos==1.65.0 \ - --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ - --hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0 +googleapis-common-protos==1.66.0 \ + --hash=sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c \ + --hash=sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed # via # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http -grpcio==1.66.2 \ - --hash=sha256:02697eb4a5cbe5a9639f57323b4c37bcb3ab2d48cec5da3dc2f13334d72790dd \ - --hash=sha256:03b0b307ba26fae695e067b94cbb014e27390f8bc5ac7a3a39b7723fed085604 \ - --hash=sha256:05bc2ceadc2529ab0b227b1310d249d95d9001cd106aa4d31e8871ad3c428d73 \ - --hash=sha256:06de8ec0bd71be123eec15b0e0d457474931c2c407869b6c349bd9bed4adbac3 \ - --hash=sha256:0be4e0490c28da5377283861bed2941d1d20ec017ca397a5df4394d1c31a9b50 \ - --hash=sha256:12fda97ffae55e6526825daf25ad0fa37483685952b5d0f910d6405c87e3adb6 \ - --hash=sha256:1caa38fb22a8578ab8393da99d4b8641e3a80abc8fd52646f1ecc92bcb8dee34 \ - --hash=sha256:2018b053aa15782db2541ca01a7edb56a0bf18c77efed975392583725974b249 \ - --hash=sha256:20657d6b8cfed7db5e11b62ff7dfe2e12064ea78e93f1434d61888834bc86d75 \ - --hash=sha256:2335c58560a9e92ac58ff2bc5649952f9b37d0735608242973c7a8b94a6437d8 \ - --hash=sha256:31fd163105464797a72d901a06472860845ac157389e10f12631025b3e4d0453 \ - --hash=sha256:38b68498ff579a3b1ee8f93a05eb48dc2595795f2f62716e797dc24774c1aaa8 \ - --hash=sha256:3b00efc473b20d8bf83e0e1ae661b98951ca56111feb9b9611df8efc4fe5d55d \ - --hash=sha256:3ed71e81782966ffead60268bbda31ea3f725ebf8aa73634d5dda44f2cf3fb9c \ - --hash=sha256:45a3d462826f4868b442a6b8fdbe8b87b45eb4f5b5308168c156b21eca43f61c \ - --hash=sha256:49f0ca7ae850f59f828a723a9064cadbed90f1ece179d375966546499b8a2c9c \ - --hash=sha256:4e504572433f4e72b12394977679161d495c4c9581ba34a88d843eaf0f2fbd39 \ - --hash=sha256:4ea1d062c9230278793820146c95d038dc0f468cbdd172eec3363e42ff1c7d01 \ - --hash=sha256:563588c587b75c34b928bc428548e5b00ea38c46972181a4d8b75ba7e3f24231 \ - --hash=sha256:6001e575b8bbd89eee11960bb640b6da6ae110cf08113a075f1e2051cc596cae \ - --hash=sha256:66a0cd8ba6512b401d7ed46bb03f4ee455839957f28b8d61e7708056a806ba6a \ - --hash=sha256:6851de821249340bdb100df5eacfecfc4e6075fa85c6df7ee0eb213170ec8e5d \ - --hash=sha256:728bdf36a186e7f51da73be7f8d09457a03061be848718d0edf000e709418987 \ - --hash=sha256:73e3b425c1e155730273f73e419de3074aa5c5e936771ee0e4af0814631fb30a \ - --hash=sha256:73fc8f8b9b5c4a03e802b3cd0c18b2b06b410d3c1dcbef989fdeb943bd44aff7 \ - --hash=sha256:78fa51ebc2d9242c0fc5db0feecc57a9943303b46664ad89921f5079e2e4ada7 \ - --hash=sha256:7b2c86457145ce14c38e5bf6bdc19ef88e66c5fee2c3d83285c5aef026ba93b3 \ - --hash=sha256:7d69ce1f324dc2d71e40c9261d3fdbe7d4c9d60f332069ff9b2a4d8a257c7b2b \ - --hash=sha256:802d84fd3d50614170649853d121baaaa305de7b65b3e01759247e768d691ddf \ - --hash=sha256:80fd702ba7e432994df208f27514280b4b5c6843e12a48759c9255679ad38db8 \ - --hash=sha256:8ac475e8da31484efa25abb774674d837b343afb78bb3bcdef10f81a93e3d6bf \ - --hash=sha256:950da58d7d80abd0ea68757769c9db0a95b31163e53e5bb60438d263f4bed7b7 \ - --hash=sha256:99a641995a6bc4287a6315989ee591ff58507aa1cbe4c2e70d88411c4dcc0839 \ - --hash=sha256:9c3a99c519f4638e700e9e3f83952e27e2ea10873eecd7935823dab0c1c9250e \ - --hash=sha256:9c509a4f78114cbc5f0740eb3d7a74985fd2eff022971bc9bc31f8bc93e66a3b \ - --hash=sha256:a18e20d8321c6400185b4263e27982488cb5cdd62da69147087a76a24ef4e7e3 \ - --hash=sha256:a917d26e0fe980b0ac7bfcc1a3c4ad6a9a4612c911d33efb55ed7833c749b0ee \ - --hash=sha256:a9539f01cb04950fd4b5ab458e64a15f84c2acc273670072abe49a3f29bbad54 \ - --hash=sha256:ad2efdbe90c73b0434cbe64ed372e12414ad03c06262279b104a029d1889d13e \ - --hash=sha256:b672abf90a964bfde2d0ecbce30f2329a47498ba75ce6f4da35a2f4532b7acbc \ - --hash=sha256:bbd27c24a4cc5e195a7f56cfd9312e366d5d61b86e36d46bbe538457ea6eb8dd \ - --hash=sha256:c400ba5675b67025c8a9f48aa846f12a39cf0c44df5cd060e23fda5b30e9359d \ - --hash=sha256:c408f5ef75cfffa113cacd8b0c0e3611cbfd47701ca3cdc090594109b9fcbaed \ - --hash=sha256:c806852deaedee9ce8280fe98955c9103f62912a5b2d5ee7e3eaa284a6d8d8e7 \ - --hash=sha256:ce89f5876662f146d4c1f695dda29d4433a5d01c8681fbd2539afff535da14d4 \ - --hash=sha256:d25a14af966438cddf498b2e338f88d1c9706f3493b1d73b93f695c99c5f0e2a \ - --hash=sha256:d8d4732cc5052e92cea2f78b233c2e2a52998ac40cd651f40e398893ad0d06ec \ - --hash=sha256:d9a9724a156c8ec6a379869b23ba3323b7ea3600851c91489b871e375f710bc8 \ - --hash=sha256:e636ce23273683b00410f1971d209bf3689238cf5538d960adc3cdfe80dd0dbd \ - --hash=sha256:e88264caad6d8d00e7913996030bac8ad5f26b7411495848cc218bd3a9040b6c \ - --hash=sha256:f145cc21836c332c67baa6fc81099d1d27e266401565bf481948010d6ea32d46 \ - --hash=sha256:fb57870449dfcfac428afbb5a877829fcb0d6db9d9baa1148705739e9083880e \ - --hash=sha256:fb70487c95786e345af5e854ffec8cb8cc781bcc5df7930c4fbb7feaa72e1cdf \ - --hash=sha256:fe96281713168a3270878255983d2cb1a97e034325c8c2c25169a69289d3ecfa \ - --hash=sha256:ff1f7882e56c40b0d33c4922c15dfa30612f05fb785074a012f7cda74d1c3679 +grpcio==1.68.0 \ + --hash=sha256:0d230852ba97654453d290e98d6aa61cb48fa5fafb474fb4c4298d8721809354 \ + --hash=sha256:0efbbd849867e0e569af09e165363ade75cf84f5229b2698d53cf22c7a4f9e21 \ + --hash=sha256:14331e5c27ed3545360464a139ed279aa09db088f6e9502e95ad4bfa852bb116 \ + --hash=sha256:15327ab81131ef9b94cb9f45b5bd98803a179c7c61205c8c0ac9aff9d6c4e82a \ + --hash=sha256:15377bce516b1c861c35e18eaa1c280692bf563264836cece693c0f169b48829 \ + --hash=sha256:15fa1fe25d365a13bc6d52fcac0e3ee1f9baebdde2c9b3b2425f8a4979fccea1 \ + --hash=sha256:18668e36e7f4045820f069997834e94e8275910b1f03e078a6020bd464cb2363 \ + --hash=sha256:2af76ab7c427aaa26aa9187c3e3c42f38d3771f91a20f99657d992afada2294a \ + --hash=sha256:2bddd04a790b69f7a7385f6a112f46ea0b34c4746f361ebafe9ca0be567c78e9 \ + --hash=sha256:32a9cb4686eb2e89d97022ecb9e1606d132f85c444354c17a7dbde4a455e4a3b \ + --hash=sha256:3ac7f10850fd0487fcce169c3c55509101c3bde2a3b454869639df2176b60a03 \ + --hash=sha256:3b2b559beb2d433129441783e5f42e3be40a9e1a89ec906efabf26591c5cd415 \ + --hash=sha256:4028b8e9a3bff6f377698587d642e24bd221810c06579a18420a17688e421af7 \ + --hash=sha256:44bcbebb24363d587472089b89e2ea0ab2e2b4df0e4856ba4c0b087c82412121 \ + --hash=sha256:46a2d74d4dd8993151c6cd585594c082abe74112c8e4175ddda4106f2ceb022f \ + --hash=sha256:4df81d78fd1646bf94ced4fb4cd0a7fe2e91608089c522ef17bc7db26e64effd \ + --hash=sha256:4e300e6978df0b65cc2d100c54e097c10dfc7018b9bd890bbbf08022d47f766d \ + --hash=sha256:4f1931c7aa85be0fa6cea6af388e576f3bf6baee9e5d481c586980c774debcb4 \ + --hash=sha256:50992f214264e207e07222703c17d9cfdcc2c46ed5a1ea86843d440148ebbe10 \ + --hash=sha256:55d3b52fd41ec5772a953612db4e70ae741a6d6ed640c4c89a64f017a1ac02b5 \ + --hash=sha256:5a180328e92b9a0050958ced34dddcb86fec5a8b332f5a229e353dafc16cd332 \ + --hash=sha256:619b5d0f29f4f5351440e9343224c3e19912c21aeda44e0c49d0d147a8d01544 \ + --hash=sha256:6b2f98165ea2790ea159393a2246b56f580d24d7da0d0342c18a085299c40a75 \ + --hash=sha256:6f9c7ad1a23e1047f827385f4713b5b8c6c7d325705be1dd3e31fb00dcb2f665 \ + --hash=sha256:79f81b7fbfb136247b70465bd836fa1733043fdee539cd6031cb499e9608a110 \ + --hash=sha256:7e0a3e72c0e9a1acab77bef14a73a416630b7fd2cbd893c0a873edc47c42c8cd \ + --hash=sha256:7e7483d39b4a4fddb9906671e9ea21aaad4f031cdfc349fec76bdfa1e404543a \ + --hash=sha256:88fb2925789cfe6daa20900260ef0a1d0a61283dfb2d2fffe6194396a354c618 \ + --hash=sha256:8af6137cc4ae8e421690d276e7627cfc726d4293f6607acf9ea7260bd8fc3d7d \ + --hash=sha256:8b0ff09c81e3aded7a183bc6473639b46b6caa9c1901d6f5e2cba24b95e59e30 \ + --hash=sha256:8c73f9fbbaee1a132487e31585aa83987ddf626426d703ebcb9a528cf231c9b1 \ + --hash=sha256:99f06232b5c9138593ae6f2e355054318717d32a9c09cdc5a2885540835067a1 \ + --hash=sha256:9fe1b141cda52f2ca73e17d2d3c6a9f3f3a0c255c216b50ce616e9dca7e3441d \ + --hash=sha256:a17278d977746472698460c63abf333e1d806bd41f2224f90dbe9460101c9796 \ + --hash=sha256:a59f5822f9459bed098ffbceb2713abbf7c6fd13f2b9243461da5c338d0cd6c3 \ + --hash=sha256:a6213d2f7a22c3c30a479fb5e249b6b7e648e17f364598ff64d08a5136fe488b \ + --hash=sha256:a831dcc343440969aaa812004685ed322cdb526cd197112d0db303b0da1e8659 \ + --hash=sha256:afbf45a62ba85a720491bfe9b2642f8761ff348006f5ef67e4622621f116b04a \ + --hash=sha256:b0cf343c6f4f6aa44863e13ec9ddfe299e0be68f87d68e777328bff785897b05 \ + --hash=sha256:c03d89df516128febc5a7e760d675b478ba25802447624edf7aa13b1e7b11e2a \ + --hash=sha256:c1245651f3c9ea92a2db4f95d37b7597db6b246d5892bca6ee8c0e90d76fb73c \ + --hash=sha256:cc5f0a4f5904b8c25729a0498886b797feb817d1fd3812554ffa39551112c161 \ + --hash=sha256:dba037ff8d284c8e7ea9a510c8ae0f5b016004f13c3648f72411c464b67ff2fb \ + --hash=sha256:def1a60a111d24376e4b753db39705adbe9483ef4ca4761f825639d884d5da78 \ + --hash=sha256:e0d2f68eaa0a755edd9a47d40e50dba6df2bceda66960dee1218da81a2834d27 \ + --hash=sha256:e0d30f3fee9372796f54d3100b31ee70972eaadcc87314be369360248a3dcffe \ + --hash=sha256:e18589e747c1e70b60fab6767ff99b2d0c359ea1db8a2cb524477f93cdbedf5b \ + --hash=sha256:e1e7ed311afb351ff0d0e583a66fcb39675be112d61e7cfd6c8269884a98afbc \ + --hash=sha256:e46541de8425a4d6829ac6c5d9b16c03c292105fe9ebf78cb1c31e8d242f9155 \ + --hash=sha256:e694b5928b7b33ca2d3b4d5f9bf8b5888906f181daff6b406f4938f3a997a490 \ + --hash=sha256:f60fa2adf281fd73ae3a50677572521edca34ba373a45b457b5ebe87c2d01e1d \ + --hash=sha256:f84890b205692ea813653ece4ac9afa2139eae136e419231b0eec7c39fdbe4c2 \ + --hash=sha256:f8f695d9576ce836eab27ba7401c60acaf9ef6cf2f70dfe5462055ba3df02cc3 \ + --hash=sha256:fc05759ffbd7875e0ff2bd877be1438dfe97c9312bbc558c8284a9afa1d0f40e \ + --hash=sha256:fd2c2d47969daa0e27eadaf15c13b5e92605c5e5953d23c06d0b5239a2f176d3 # via # -r src/backend/requirements.in # opentelemetry-exporter-otlp-proto-grpc @@ -732,17 +768,17 @@ html5lib==1.1 \ --hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d \ --hash=sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f # via weasyprint -icalendar==6.0.1 \ - --hash=sha256:1ff44825d7b41c3f77eac9e09cc67a770dd3c2377430c23b0eb7d91603088892 \ - --hash=sha256:9bf3d69203bd0366a9a29a8b0e220574580b86d7918afcb628fc6920287922f3 +icalendar==6.1.0 \ + --hash=sha256:43c2db8632959d634f4e48f6e6131e706bf2cdddad488cf0b72fda079b796bad \ + --hash=sha256:46c09b774a6e6948495dafcb166dc15135c8259d0ae25491f154cbc822714b69 # via django-ical idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==8.4.0 \ - --hash=sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1 \ - --hash=sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5 +importlib-metadata==8.5.0 \ + --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ + --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 # via # django-q2 # markdown @@ -920,68 +956,68 @@ markdown==3.7 \ markuppy==1.14 \ --hash=sha256:1adee2c0a542af378fe84548ff6f6b0168f3cb7f426b46961038a2bcfaad0d5f # via tablib -markupsafe==3.0.1 \ - --hash=sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396 \ - --hash=sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38 \ - --hash=sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a \ - --hash=sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8 \ - --hash=sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b \ - --hash=sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad \ - --hash=sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a \ - --hash=sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a \ - --hash=sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da \ - --hash=sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6 \ - --hash=sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8 \ - --hash=sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344 \ - --hash=sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a \ - --hash=sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8 \ - --hash=sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5 \ - --hash=sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7 \ - --hash=sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170 \ - --hash=sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132 \ - --hash=sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9 \ - --hash=sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd \ - --hash=sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9 \ - --hash=sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346 \ - --hash=sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc \ - --hash=sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589 \ - --hash=sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5 \ - --hash=sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915 \ - --hash=sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295 \ - --hash=sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453 \ - --hash=sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea \ - --hash=sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b \ - --hash=sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d \ - --hash=sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b \ - --hash=sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4 \ - --hash=sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b \ - --hash=sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7 \ - --hash=sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf \ - --hash=sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f \ - --hash=sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91 \ - --hash=sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd \ - --hash=sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50 \ - --hash=sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b \ - --hash=sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583 \ - --hash=sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a \ - --hash=sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984 \ - --hash=sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c \ - --hash=sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c \ - --hash=sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25 \ - --hash=sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa \ - --hash=sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4 \ - --hash=sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3 \ - --hash=sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97 \ - --hash=sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1 \ - --hash=sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd \ - --hash=sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772 \ - --hash=sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a \ - --hash=sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729 \ - --hash=sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca \ - --hash=sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6 \ - --hash=sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635 \ - --hash=sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b \ - --hash=sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f +markupsafe==3.0.2 \ + --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ + --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ + --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ + --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ + --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ + --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ + --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ + --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ + --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ + --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ + --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ + --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ + --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ + --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ + --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ + --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ + --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ + --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ + --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ + --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ + --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ + --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ + --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ + --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ + --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ + --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ + --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ + --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ + --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ + --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ + --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ + --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ + --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ + --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via jinja2 odfpy==1.4.1 \ --hash=sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec @@ -990,9 +1026,9 @@ openpyxl==3.1.5 \ --hash=sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2 \ --hash=sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050 # via tablib -opentelemetry-api==1.27.0 \ - --hash=sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7 \ - --hash=sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342 +opentelemetry-api==1.28.2 \ + --hash=sha256:6fcec89e265beb258fe6b1acaaa3c8c705a934bd977b9f534a2b7c0d2d4275a6 \ + --hash=sha256:ecdc70c7139f17f9b0cf3742d57d7020e3e8315d6cffcdf1a12a905d45b19cc0 # via # -r src/backend/requirements.in # opentelemetry-exporter-otlp-proto-grpc @@ -1004,167 +1040,165 @@ opentelemetry-api==1.27.0 \ # opentelemetry-instrumentation-wsgi # opentelemetry-sdk # opentelemetry-semantic-conventions -opentelemetry-exporter-otlp==1.27.0 \ - --hash=sha256:4a599459e623868cc95d933c301199c2367e530f089750e115599fccd67cb2a1 \ - --hash=sha256:7688791cbdd951d71eb6445951d1cfbb7b6b2d7ee5948fac805d404802931145 +opentelemetry-exporter-otlp==1.28.2 \ + --hash=sha256:45f8d7fe4cdd41526464b542ce91b1fd1ae661be92d2c6cba71a3d948b2bdf70 \ + --hash=sha256:b50f6d4a80e6bcd329e36f360ac486ecfa106ea704d6226ceea05d3a48455f70 # via -r src/backend/requirements.in -opentelemetry-exporter-otlp-proto-common==1.27.0 \ - --hash=sha256:159d27cf49f359e3798c4c3eb8da6ef4020e292571bd8c5604a2a573231dd5c8 \ - --hash=sha256:675db7fffcb60946f3a5c43e17d1168a3307a94a930ecf8d2ea1f286f3d4f79a +opentelemetry-exporter-otlp-proto-common==1.28.2 \ + --hash=sha256:545b1943b574f666c35b3d6cc67cb0b111060727e93a1e2866e346b33bff2a12 \ + --hash=sha256:7aebaa5fc9ff6029374546df1f3a62616fda07fccd9c6a8b7892ec130dd8baca # via # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http -opentelemetry-exporter-otlp-proto-grpc==1.27.0 \ - --hash=sha256:56b5bbd5d61aab05e300d9d62a6b3c134827bbd28d0b12f2649c2da368006c9e \ - --hash=sha256:af6f72f76bcf425dfb5ad11c1a6d6eca2863b91e63575f89bb7b4b55099d968f +opentelemetry-exporter-otlp-proto-grpc==1.28.2 \ + --hash=sha256:07c10378380bbb01a7f621a5ce833fc1fab816e971140cd3ea1cd587840bc0e6 \ + --hash=sha256:6083d9300863aab35bfce7c172d5fc1007686e6f8dff366eae460cd9a21592e2 # via opentelemetry-exporter-otlp -opentelemetry-exporter-otlp-proto-http==1.27.0 \ - --hash=sha256:2103479092d8eb18f61f3fbff084f67cc7f2d4a7d37e75304b8b56c1d09ebef5 \ - --hash=sha256:688027575c9da42e179a69fe17e2d1eba9b14d81de8d13553a21d3114f3b4d75 +opentelemetry-exporter-otlp-proto-http==1.28.2 \ + --hash=sha256:af921c18212a56ef4be68458ba475791c0517ebfd8a2ff04669c9cd477d90ff2 \ + --hash=sha256:d9b353d67217f091aaf4cfe8693c170973bb3e90a558992570d97020618fda79 # via opentelemetry-exporter-otlp -opentelemetry-instrumentation==0.48b0 \ - --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ - --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 +opentelemetry-instrumentation==0.49b2 \ + --hash=sha256:8cf00cc8d9d479e4b72adb9bd267ec544308c602b7188598db5a687e77b298e2 \ + --hash=sha256:f6d782b0ef9fef4a4c745298651c65f5c532c34cd4c40d230ab5b9f3b3b4d151 # via # opentelemetry-instrumentation-django # opentelemetry-instrumentation-redis # opentelemetry-instrumentation-requests # opentelemetry-instrumentation-wsgi -opentelemetry-instrumentation-django==0.48b0 \ - --hash=sha256:d31fca8bdf5a75e004a459f2eb3fcba707fbb0a39fc3d3c520c38265775cb9df \ - --hash=sha256:e6742744ee1cfbfee8a6b57182a2071475531b79863411e1eb5f0d5b5322b7b4 +opentelemetry-instrumentation-django==0.49b2 \ + --hash=sha256:7011ee87dba4a843f97d0690c4fa1213eab5dcb70596288f1471d5f37756da63 \ + --hash=sha256:71544b2340551d6fe95b965be68d0fe6552f6c36d2b13d269a2cb345133c73e6 # via -r src/backend/requirements.in -opentelemetry-instrumentation-redis==0.48b0 \ - --hash=sha256:48c7f2e25cbb30bde749dc0d8b9c74c404c851f554af832956b9630b27f5bcb7 \ - --hash=sha256:61e33e984b4120e1b980d9fba6e9f7ca0c8d972f9970654d8f6e9f27fa115a8c +opentelemetry-instrumentation-redis==0.49b2 \ + --hash=sha256:2e4e6058e2074c8124c8107a6be40b6edfbba59c740280d9cd30ab733f3bc646 \ + --hash=sha256:7a966aa85e68990e82d4ffd45a55b270a54599c8e303c89f49ce11ef78d32b48 # via -r src/backend/requirements.in -opentelemetry-instrumentation-requests==0.48b0 \ - --hash=sha256:67ab9bd877a0352ee0db4616c8b4ae59736ddd700c598ed907482d44f4c9a2b3 \ - --hash=sha256:d4f01852121d0bd4c22f14f429654a735611d4f7bf3cf93f244bdf1489b2233d +opentelemetry-instrumentation-requests==0.49b2 \ + --hash=sha256:d49b0022b29fb7f07a38b8e68750304c29a6d6114b94b56e3e811eff59efd318 \ + --hash=sha256:ea7216f13f42d3220ccd60cefd104fae656c9206bf5e3030d59fa367a9452e99 # via -r src/backend/requirements.in -opentelemetry-instrumentation-wsgi==0.48b0 \ - --hash=sha256:1a1e752367b0df4397e0b835839225ef5c2c3c053743a261551af13434fc4d51 \ - --hash=sha256:c6051124d741972090fe94b2fa302555e1e2a22e9cdda32dd39ed49a5b34e0c6 +opentelemetry-instrumentation-wsgi==0.49b2 \ + --hash=sha256:0bd88510fa45fa6ba70bd444060c0a1ee12e45e02bb4bcba19bc4f955269b872 \ + --hash=sha256:95ff5133cc15e5fed102ac725ad210be82a4b93a3bc740ddae4b5bbdb771b21d # via opentelemetry-instrumentation-django -opentelemetry-proto==1.27.0 \ - --hash=sha256:33c9345d91dafd8a74fc3d7576c5a38f18b7fdf8d02983ac67485386132aedd6 \ - --hash=sha256:b133873de5581a50063e1e4b29cdcf0c5e253a8c2d8dc1229add20a4c3830ace +opentelemetry-proto==1.28.2 \ + --hash=sha256:0837498f59db55086462915e5898d0b1a18c1392f6db4d7e937143072a72370c \ + --hash=sha256:7c0d125a6b71af88bfeeda16bfdd0ff63dc2cf0039baf6f49fa133b203e3f566 # via # opentelemetry-exporter-otlp-proto-common # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http -opentelemetry-sdk==1.27.0 \ - --hash=sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d \ - --hash=sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f +opentelemetry-sdk==1.28.2 \ + --hash=sha256:5fed24c5497e10df30282456fe2910f83377797511de07d14cec0d3e0a1a3110 \ + --hash=sha256:93336c129556f1e3ccd21442b94d3521759541521861b2214c499571b85cb71b # via # -r src/backend/requirements.in # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http -opentelemetry-semantic-conventions==0.48b0 \ - --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ - --hash=sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f +opentelemetry-semantic-conventions==0.49b2 \ + --hash=sha256:44e32ce6a5bb8d7c0c617f84b9dc1c8deda1045a07dc16a688cc7cbeab679997 \ + --hash=sha256:51e7e1d0daa958782b6c2a8ed05e5f0e7dd0716fc327ac058777b8659649ee54 # via + # opentelemetry-instrumentation # opentelemetry-instrumentation-django # opentelemetry-instrumentation-redis # opentelemetry-instrumentation-requests # opentelemetry-instrumentation-wsgi # opentelemetry-sdk -opentelemetry-util-http==0.48b0 \ - --hash=sha256:60312015153580cc20f322e5cdc3d3ecad80a71743235bdb77716e742814623c \ - --hash=sha256:76f598af93aab50328d2a69c786beaedc8b6a7770f7a818cc307eb353debfffb +opentelemetry-util-http==0.49b2 \ + --hash=sha256:5958c7009f79146bbe98b0fdb23d9d7bf1ea9cd154a1c199029b1a89e0557199 \ + --hash=sha256:e325d6511c6bee7b43170eb0c93261a210ec57e20ab1d7a99838515ef6d2bf58 # via # opentelemetry-instrumentation-django # opentelemetry-instrumentation-requests # opentelemetry-instrumentation-wsgi -packaging==24.1 \ - --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ - --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 - # via gunicorn +packaging==24.2 \ + --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ + --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f + # via + # gunicorn + # opentelemetry-instrumentation pdf2image==1.17.0 \ --hash=sha256:eaa959bc116b420dd7ec415fcae49b98100dda3dd18cd2fdfa86d09f112f6d57 \ --hash=sha256:ecdd58d7afb810dffe21ef2b1bbc057ef434dabbac6c33778a38a3f7744a27e2 # via -r src/backend/requirements.in -pillow==10.4.0 \ - --hash=sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885 \ - --hash=sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea \ - --hash=sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df \ - --hash=sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5 \ - --hash=sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c \ - --hash=sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d \ - --hash=sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd \ - --hash=sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06 \ - --hash=sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908 \ - --hash=sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a \ - --hash=sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be \ - --hash=sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0 \ - --hash=sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b \ - --hash=sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80 \ - --hash=sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a \ - --hash=sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e \ - --hash=sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9 \ - --hash=sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696 \ - --hash=sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b \ - --hash=sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309 \ - --hash=sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e \ - --hash=sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab \ - --hash=sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d \ - --hash=sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060 \ - --hash=sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d \ - --hash=sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d \ - --hash=sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4 \ - --hash=sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3 \ - --hash=sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6 \ - --hash=sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb \ - --hash=sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94 \ - --hash=sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b \ - --hash=sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496 \ - --hash=sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0 \ - --hash=sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319 \ - --hash=sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b \ - --hash=sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856 \ - --hash=sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef \ - --hash=sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680 \ - --hash=sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b \ - --hash=sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42 \ - --hash=sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e \ - --hash=sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597 \ - --hash=sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a \ - --hash=sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8 \ - --hash=sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3 \ - --hash=sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736 \ - --hash=sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da \ - --hash=sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126 \ - --hash=sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd \ - --hash=sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5 \ - --hash=sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b \ - --hash=sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026 \ - --hash=sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b \ - --hash=sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc \ - --hash=sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46 \ - --hash=sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2 \ - --hash=sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c \ - --hash=sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe \ - --hash=sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984 \ - --hash=sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a \ - --hash=sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70 \ - --hash=sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca \ - --hash=sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b \ - --hash=sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91 \ - --hash=sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3 \ - --hash=sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84 \ - --hash=sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1 \ - --hash=sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5 \ - --hash=sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be \ - --hash=sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f \ - --hash=sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc \ - --hash=sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9 \ - --hash=sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e \ - --hash=sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141 \ - --hash=sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef \ - --hash=sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22 \ - --hash=sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27 \ - --hash=sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e \ - --hash=sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1 +pillow==11.0.0 \ + --hash=sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7 \ + --hash=sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5 \ + --hash=sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903 \ + --hash=sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2 \ + --hash=sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38 \ + --hash=sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2 \ + --hash=sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9 \ + --hash=sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f \ + --hash=sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc \ + --hash=sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8 \ + --hash=sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d \ + --hash=sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2 \ + --hash=sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316 \ + --hash=sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a \ + --hash=sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25 \ + --hash=sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd \ + --hash=sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba \ + --hash=sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc \ + --hash=sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273 \ + --hash=sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa \ + --hash=sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a \ + --hash=sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b \ + --hash=sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a \ + --hash=sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae \ + --hash=sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291 \ + --hash=sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97 \ + --hash=sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06 \ + --hash=sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904 \ + --hash=sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b \ + --hash=sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b \ + --hash=sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8 \ + --hash=sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527 \ + --hash=sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947 \ + --hash=sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb \ + --hash=sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003 \ + --hash=sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5 \ + --hash=sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f \ + --hash=sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739 \ + --hash=sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944 \ + --hash=sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830 \ + --hash=sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f \ + --hash=sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3 \ + --hash=sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4 \ + --hash=sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84 \ + --hash=sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7 \ + --hash=sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6 \ + --hash=sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6 \ + --hash=sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9 \ + --hash=sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de \ + --hash=sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4 \ + --hash=sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47 \ + --hash=sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd \ + --hash=sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50 \ + --hash=sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c \ + --hash=sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086 \ + --hash=sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba \ + --hash=sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306 \ + --hash=sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699 \ + --hash=sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e \ + --hash=sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488 \ + --hash=sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa \ + --hash=sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2 \ + --hash=sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3 \ + --hash=sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9 \ + --hash=sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923 \ + --hash=sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2 \ + --hash=sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790 \ + --hash=sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734 \ + --hash=sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916 \ + --hash=sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1 \ + --hash=sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f \ + --hash=sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798 \ + --hash=sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb \ + --hash=sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2 \ + --hash=sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9 # via # -r src/backend/requirements.in # django-stdimage @@ -1172,30 +1206,34 @@ pillow==10.4.0 \ # python-barcode # qrcode # weasyprint -pint==0.24.3 \ - --hash=sha256:d54771093e8b94c4e0a35ac638c2444ddf3ef685652bab7675ffecfa0c5c5cdf \ - --hash=sha256:d98667e46fd03a1b94694fbfa104ec30858684d8ab26952e2a348b48059089bb +pint==0.24.4 \ + --hash=sha256:35275439b574837a6cd3020a5a4a73645eb125ce4152a73a2f126bf164b91b80 \ + --hash=sha256:aa54926c8772159fcf65f82cc0d34de6768c151b32ad1deb0331291c38fe7659 # via -r src/backend/requirements.in pip-licenses==5.0.0 \ --hash=sha256:0633a1f9aab58e5a6216931b0e1d5cdded8bcc2709ff563674eb0e2ff9e77e8e \ --hash=sha256:82c83666753efb86d1af1c405c8ab273413eb10d6689c218df2f09acf40e477d # via -r src/backend/requirements.in -prettytable==3.11.0 \ - --hash=sha256:7e23ca1e68bbfd06ba8de98bf553bf3493264c96d5e8a615c0471025deeba722 \ - --hash=sha256:aa17083feb6c71da11a68b2c213b04675c4af4ce9c541762632ca3f2cb3546dd +platformdirs==4.3.6 \ + --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ + --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb + # via pint +prettytable==3.12.0 \ + --hash=sha256:77ca0ad1c435b6e363d7e8623d7cc4fcf2cf15513bf77a1c1b2e814930ac57cc \ + --hash=sha256:f04b3e1ba35747ac86e96ec33e3bb9748ce08e254dc2a1c6253945901beec804 # via pip-licenses -protobuf==4.25.5 \ - --hash=sha256:0aebecb809cae990f8129ada5ca273d9d670b76d9bfc9b1809f0a9c02b7dbf41 \ - --hash=sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea \ - --hash=sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8 \ - --hash=sha256:7a183f592dc80aa7c8da7ad9e55091c4ffc9497b3054452d629bb85fa27c2a45 \ - --hash=sha256:7f8249476b4a9473645db7f8ab42b02fe1488cbe5fb72fddd445e0665afd8584 \ - --hash=sha256:919ad92d9b0310070f8356c24b855c98df2b8bd207ebc1c0c6fcc9ab1e007f3d \ - --hash=sha256:98d8d8aa50de6a2747efd9cceba361c9034050ecce3e09136f90de37ddba66e1 \ - --hash=sha256:abe32aad8561aa7cc94fc7ba4fdef646e576983edb94a73381b03c53728a626f \ - --hash=sha256:b0234dd5a03049e4ddd94b93400b67803c823cfc405689688f59b34e0742381a \ - --hash=sha256:b2fde3d805354df675ea4c7c6338c1aecd254dfc9925e88c6d31a2bcb97eb173 \ - --hash=sha256:fe14e16c22be926d3abfcb500e60cab068baf10b542b8c858fa27e098123e331 +protobuf==5.28.3 \ + --hash=sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24 \ + --hash=sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535 \ + --hash=sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b \ + --hash=sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548 \ + --hash=sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584 \ + --hash=sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b \ + --hash=sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36 \ + --hash=sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135 \ + --hash=sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868 \ + --hash=sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687 \ + --hash=sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed # via # googleapis-common-protos # opentelemetry-proto @@ -1213,13 +1251,13 @@ pydyf==0.10.0 \ # via # -r src/backend/requirements.in # weasyprint -pyjwt==2.9.0 \ - --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \ - --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c +pyjwt==2.10.0 \ + --hash=sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15 \ + --hash=sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c # via djangorestframework-simplejwt -pyphen==0.16.0 \ - --hash=sha256:2c006b3ddf072c9571ab97606d9ab3c26a92eaced4c0d59fd1d26988f308f413 \ - --hash=sha256:b4a4c6d7d5654b698b5fc68123148bb799b3debe0175d1d5dc3edfe93066fc4c +pyphen==0.17.0 \ + --hash=sha256:1d13acd1ce37a384d7612954ae6c7801bb4c5316da0e2b937b2127ba702a3da4 \ + --hash=sha256:dad0b2e4aa80f6d70bf06711b2da36c47a756b933c1d0c4cbbab40f643a5958c # via weasyprint python-barcode[images]==0.15.1 \ --hash=sha256:057636fba37369c22852410c8535b36adfbeb965ddfd4e5b6924455d692e0886 \ @@ -1322,99 +1360,99 @@ qrcode[pil]==8.0 \ # via # -r src/backend/requirements.in # django-allauth-2fa -rapidfuzz==3.10.0 \ - --hash=sha256:094c26116d55bf9c53abd840d08422f20da78ec4c4723e5024322321caedca48 \ - --hash=sha256:0ec338d5f4ad8d9339a88a08db5c23e7f7a52c2b2a10510c48a0cef1fb3f0ddc \ - --hash=sha256:10fdad800441b9c97d471a937ba7d42625f1b530db05e572f1cb7d401d95c893 \ - --hash=sha256:116c71a81e046ba56551d8ab68067ca7034d94b617545316d460a452c5c3c289 \ - --hash=sha256:1af60988d47534246d9525f77288fdd9de652608a4842815d9018570b959acc6 \ - --hash=sha256:2026651761bf83a0f31495cc0f70840d5c0d54388f41316e3f9cb51bd85e49a5 \ - --hash=sha256:20bd153aacc244e4c907d772c703fea82754c4db14f8aa64d75ff81b7b8ab92d \ - --hash=sha256:26de93e6495078b6af4c4d93a42ca067b16cc0e95699526c82ab7d1025b4d3bf \ - --hash=sha256:288f6f6e7410cacb115fb851f3f18bf0e4231eb3f6cb5bd1cec0e7b25c4d039d \ - --hash=sha256:2db9187f3acf3cd33424ecdbaad75414c298ecd1513470df7bda885dcb68cc15 \ - --hash=sha256:2e9be5d05cd960914024412b5406fb75a82f8562f45912ff86255acbfdbfb78e \ - --hash=sha256:2fe5783676f0afba4a522c80b15e99dbf4e393c149ab610308a8ef1f04c6bcc8 \ - --hash=sha256:3084161fc3e963056232ef8d937449a2943852e07101f5a136c8f3cfa4119217 \ - --hash=sha256:34f213d59219a9c3ca14e94a825f585811a68ac56b4118b4dc388b5b14afc108 \ - --hash=sha256:399b9b79ccfcf50ca3bad7692bc098bb8eade88d7d5e15773b7f866c91156d0c \ - --hash=sha256:43dfc5e733808962a822ff6d9c29f3039a3cfb3620706f5953e17cfe4496724c \ - --hash=sha256:457827ba82261aa2ae6ac06a46d0043ab12ba7216b82d87ae1434ec0f29736d6 \ - --hash=sha256:47aca565a39c9a6067927871973ca827023e8b65ba6c5747f4c228c8d7ddc04f \ - --hash=sha256:4bd1a7676ee2a4c8e2f7f2550bece994f9f89e58afb96088964145a83af7408b \ - --hash=sha256:4dd3d8443970eaa02ab5ae45ce584b061f2799cd9f7e875190e2617440c1f9d4 \ - --hash=sha256:4df75b3ebbb8cfdb9bf8b213b168620b88fd92d0c16a8bc9f9234630b282db59 \ - --hash=sha256:50484d563f8bfa723c74c944b0bb15b9e054db9c889348c8c307abcbee75ab92 \ - --hash=sha256:50e3d0c72ea15391ba9531ead7f2068a67c5b18a6a365fef3127583aaadd1725 \ - --hash=sha256:545fc04f2d592e4350f59deb0818886c1b444ffba3bec535b4fbb97191aaf769 \ - --hash=sha256:56fd15ea8f4c948864fa5ebd9261c67cf7b89a1c517a0caef4df75446a7af18c \ - --hash=sha256:5897242d455461f2c5b82d7397b29341fd11e85bf3608a522177071044784ee8 \ - --hash=sha256:5d350864269d56f51ab81ab750c9259ae5cad3152c0680baef143dcec92206a1 \ - --hash=sha256:5dd6eec15b13329abe66cc241b484002ecb0e17d694491c944a22410a6a9e5e2 \ - --hash=sha256:63e4c175cbce8c3adc22dca5e6154588ae673f6c55374d156f3dac732c88d7de \ - --hash=sha256:69ef5b363afff7150a1fbe788007e307b9802a2eb6ad92ed51ab94e6ad2674c6 \ - --hash=sha256:6b62af27e65bb39276a66533655a2fa3c60a487b03935721c45b7809527979be \ - --hash=sha256:6cd67d3d017296d98ff505529104299f78433e4b8af31b55003d901a62bbebe9 \ - --hash=sha256:718c9bd369288aca5fa929df6dbf66fdbe9768d90940a940c0b5cdc96ade4309 \ - --hash=sha256:76a35e9e19a7c883c422ffa378e9a04bc98cb3b29648c5831596401298ee51e6 \ - --hash=sha256:7947a425d1be3e744707ee58c6cb318b93a56e08f080722dcc0347e0b7a1bb9a \ - --hash=sha256:79e7f98525b60b3c14524e0a4e1fedf7654657b6e02eb25f1be897ab097706f3 \ - --hash=sha256:7c4c82b1689b23b1b5e6a603164ed2be41b6f6de292a698b98ba2381e889eb9d \ - --hash=sha256:7dc87073ba3a40dd65591a2100aa71602107443bf10770579ff9c8a3242edb94 \ - --hash=sha256:7f3a6aa6e70fc27e4ff5c479f13cc9fc26a56347610f5f8b50396a0d344c5f55 \ - --hash=sha256:803f255f10d63420979b1909ef976e7d30dec42025c9b067fc1d2040cc365a7e \ - --hash=sha256:884453860de029380dded8f3c1918af2d8eb5adf8010261645c7e5c88c2b5428 \ - --hash=sha256:886882367dbc985f5736356105798f2ae6e794e671fc605476cbe2e73838a9bb \ - --hash=sha256:8a6405d34c394c65e4f73a1d300c001f304f08e529d2ed6413b46ee3037956eb \ - --hash=sha256:916a6abf3632e592b937c3d04c00a6efadd8fd30539cdcd4e6e4d92be7ca5d90 \ - --hash=sha256:9178277f72d144a6c7704d7ae7fa15b7b86f0f0796f0e1049c7b4ef748a662ef \ - --hash=sha256:949b5e9eeaa4ecb4c7e9c2a4689dddce60929dd1ff9c76a889cdbabe8bbf2171 \ - --hash=sha256:94c48b4a2a4b1d22246f48e2b11cae01ec7d23f0c9123f8bb822839ad79d0a88 \ - --hash=sha256:96ad46f5f56f70fab2be9e5f3165a21be58d633b90bf6e67fc52a856695e4bcf \ - --hash=sha256:98f6ebe28831a482981ecfeedc8237047878424ad0c1add2c7f366ba44a20452 \ - --hash=sha256:9eac95b4278bd53115903d89118a2c908398ee8bdfd977ae844f1bd2b02b917c \ - --hash=sha256:a425a0a868cf8e9c6e93e1cda4b758cdfd314bb9a4fc916c5742c934e3613480 \ - --hash=sha256:a68e3724b7dab761c01816aaa64b0903734d999d5589daf97c14ef5cc0629a8e \ - --hash=sha256:a86d5d1d75e61df060c1e56596b6b0a4422a929dff19cc3dbfd5eee762c86b61 \ - --hash=sha256:a9b8f51e08c3f983d857c3889930af9ddecc768453822076683664772d87e374 \ - --hash=sha256:aadce42147fc09dcef1afa892485311e824c050352e1aa6e47f56b9b27af4cf0 \ - --hash=sha256:ae7966f205b5a7fde93b44ca8fed37c1c8539328d7f179b1197de34eceaceb5f \ - --hash=sha256:b0445fa9880ead81f5a7d0efc0b9c977a947d8052c43519aceeaf56eabaf6843 \ - --hash=sha256:b0732343cdc4273b5921268026dd7266f75466eb21873cb7635a200d9d9c3fac \ - --hash=sha256:b11a127ac590fc991e8a02c2d7e1ac86e8141c92f78546f18b5c904064a0552c \ - --hash=sha256:b33e13e537e3afd1627d421a142a12bbbe601543558a391a6fae593356842f6e \ - --hash=sha256:b5363932a5aab67010ae1a6205c567d1ef256fb333bc23c27582481606be480c \ - --hash=sha256:b54853c2371bf0e38d67da379519deb6fbe70055efb32f6607081641af3dc752 \ - --hash=sha256:b67cc21a14327a0eb0f47bc3d7e59ec08031c7c55220ece672f9476e7a8068d3 \ - --hash=sha256:bb0013795b40db5cf361e6f21ee7cda09627cf294977149b50e217d7fe9a2f03 \ - --hash=sha256:bd393683129f446a75d8634306aed7e377627098a1286ff3af2a4f1736742820 \ - --hash=sha256:c038b9939da3035afb6cb2f465f18163e8f070aba0482923ecff9443def67178 \ - --hash=sha256:c50bc308fa29767ed8f53a8d33b7633a9e14718ced038ed89d41b886e301da32 \ - --hash=sha256:c582c46b1bb0b19f1a5f4c1312f1b640c21d78c371a6615c34025b16ee56369b \ - --hash=sha256:c77a7330dd15c7eb5fd3631dc646fc96327f98db8181138766bd14d3e905f0ba \ - --hash=sha256:c9e29a13d2fd9be3e7d8c26c7ef4ba60b5bc7efbc9dbdf24454c7e9ebba31768 \ - --hash=sha256:ca366c2e2a54e2f663f4529b189fdeb6e14d419b1c78b754ec1744f3c01070d4 \ - --hash=sha256:ce19887268e90ee81a3957eef5e46a70ecc000713796639f83828b950343f49e \ - --hash=sha256:cffbc50e0767396ed483900900dd58ce4351bc0d40e64bced8694bd41864cc71 \ - --hash=sha256:d29d1b9857c65f8cb3a29270732e1591b9bacf89de9d13fa764f79f07d8f1fd2 \ - --hash=sha256:d4688862f957c8629d557d084f20b2d803f8738b6c4066802a0b1cc472e088d9 \ - --hash=sha256:e5ddb2388610799fc46abe389600625058f2a73867e63e20107c5ad5ffa57c47 \ - --hash=sha256:e89605afebbd2d4b045bccfdc12a14b16fe8ccbae05f64b4b4c64a97dad1c891 \ - --hash=sha256:ea2da0459b951ee461bd4e02b8904890bd1c4263999d291c5cd01e6620177ad4 \ - --hash=sha256:ec9139baa3f85b65adc700eafa03ed04995ca8533dd56c924f0e458ffec044ab \ - --hash=sha256:eda4c661e68dddd56c8fbfe1ca35e40dd2afd973f7ebb1605f4d151edc63dff8 \ - --hash=sha256:f0a547e4350d1fa32624d3eab51eff8cf329f4cae110b4ea0402486b1da8be40 \ - --hash=sha256:f39a2a5ded23b9b9194ec45740dce57177b80f86c6d8eba953d3ff1a25c97766 \ - --hash=sha256:f3a0bda83c18195c361b5500377d0767749f128564ca95b42c8849fd475bb327 \ - --hash=sha256:f744b5eb1469bf92dd143d36570d2bdbbdc88fe5cb0b5405e53dd34f479cbd8a \ - --hash=sha256:f9f0bbfb6787b97c51516f3ccf97737d504db5d239ad44527673b81f598b84ab \ - --hash=sha256:fa9720e56663cc3649d62b4b5f3145e94b8f5611e8a8e1b46507777249d46aad \ - --hash=sha256:fb6ec40cef63b1922083d33bfef2f91fc0b0bc07b5b09bfee0b0f1717d558292 \ - --hash=sha256:fe5231e8afd069c742ac5b4f96344a0fe4aff52df8e53ef87faebf77f827822c +rapidfuzz==3.10.1 \ + --hash=sha256:00d02cbd75d283c287471b5b3738b3e05c9096150f93f2d2dfa10b3d700f2db9 \ + --hash=sha256:031f8b367e5d92f7a1e27f7322012f3c321c3110137b43cc3bf678505583ef48 \ + --hash=sha256:073a5b107e17ebd264198b78614c0206fa438cce749692af5bc5f8f484883f50 \ + --hash=sha256:0b75fe506c8e02769cc47f5ab21ce3e09b6211d3edaa8f8f27331cb6988779be \ + --hash=sha256:0e06d99ad1ad97cb2ef7f51ec6b1fedd74a3a700e4949353871cf331d07b382a \ + --hash=sha256:0fff4a6b87c07366662b62ae994ffbeadc472e72f725923f94b72a3db49f4671 \ + --hash=sha256:10746c1d4c8cd8881c28a87fd7ba0c9c102346dfe7ff1b0d021cdf093e9adbff \ + --hash=sha256:1340b56340896bede246f612b6ecf685f661a56aabef3d2512481bfe23ac5835 \ + --hash=sha256:18123168cba156ab5794ea6de66db50f21bb3c66ae748d03316e71b27d907b95 \ + --hash=sha256:187d9747149321607be4ccd6f9f366730078bed806178ec3eeb31d05545e9e8f \ + --hash=sha256:191633722203f5b7717efcb73a14f76f3b124877d0608c070b827c5226d0b972 \ + --hash=sha256:195baad28057ec9609e40385991004e470af9ef87401e24ebe72c064431524ab \ + --hash=sha256:1996feb7a61609fa842e6b5e0c549983222ffdedaf29644cc67e479902846dfe \ + --hash=sha256:1b35a118d61d6f008e8e3fb3a77674d10806a8972c7b8be433d6598df4d60b01 \ + --hash=sha256:1e6bbca9246d9eedaa1c84e04a7f555493ba324d52ae4d9f3d9ddd1b740dcd87 \ + --hash=sha256:1e96c84d6c2a0ca94e15acb5399118fff669f4306beb98a6d8ec6f5dccab4412 \ + --hash=sha256:2316515169b7b5a453f0ce3adbc46c42aa332cae9f2edb668e24d1fc92b2f2bb \ + --hash=sha256:231ef1ec9cf7b59809ce3301006500b9d564ddb324635f4ea8f16b3e2a1780da \ + --hash=sha256:237bec5dd1bfc9b40bbd786cd27949ef0c0eb5fab5eb491904c6b5df59d39d3c \ + --hash=sha256:26f71582c0d62445067ee338ddad99b655a8f4e4ed517a90dcbfbb7d19310474 \ + --hash=sha256:2cf44d01bfe8ee605b7eaeecbc2b9ca64fc55765f17b304b40ed8995f69d7716 \ + --hash=sha256:335fee93188f8cd585552bb8057228ce0111bd227fa81bfd40b7df6b75def8ab \ + --hash=sha256:3611c8f45379a12063d70075c75134f2a8bd2e4e9b8a7995112ddae95ca1c982 \ + --hash=sha256:365e4fc1a2b95082c890f5e98489b894e6bf8c338c6ac89bb6523c2ca6e9f086 \ + --hash=sha256:36c0e1483e21f918d0f2f26799fe5ac91c7b0c34220b73007301c4f831a9c4c7 \ + --hash=sha256:38b0dac2c8e057562b8f0d8ae5b663d2d6a28c5ab624de5b73cef9abb6129a24 \ + --hash=sha256:39c4983e2e2ccb9732f3ac7d81617088822f4a12291d416b09b8a1eadebb3e29 \ + --hash=sha256:3c3b537b97ac30da4b73930fa8a4fe2f79c6d1c10ad535c5c09726612cd6bed9 \ + --hash=sha256:425f4ac80b22153d391ee3f94bc854668a0c6c129f05cf2eaf5ee74474ddb69e \ + --hash=sha256:440b5608ab12650d0390128d6858bc839ae77ffe5edf0b33a1551f2fa9860651 \ + --hash=sha256:4ffed25f9fdc0b287f30a98467493d1e1ce5b583f6317f70ec0263b3c97dbba6 \ + --hash=sha256:54bcf4efaaee8e015822be0c2c28214815f4f6b4f70d8362cfecbd58a71188ac \ + --hash=sha256:565c2bd4f7d23c32834652b27b51dd711814ab614b4e12add8476be4e20d1cf5 \ + --hash=sha256:567f88180f2c1423b4fe3f3ad6e6310fc97b85bdba574801548597287fc07028 \ + --hash=sha256:5a15546d847a915b3f42dc79ef9b0c78b998b4e2c53b252e7166284066585979 \ + --hash=sha256:616290fb9a8fa87e48cb0326d26f98d4e29f17c3b762c2d586f2b35c1fd2034b \ + --hash=sha256:65a2fa13e8a219f9b5dcb9e74abe3ced5838a7327e629f426d333dfc8c5a6e66 \ + --hash=sha256:666d5d8b17becc3f53447bcb2b6b33ce6c2df78792495d1fa82b2924cd48701a \ + --hash=sha256:6729b856166a9e95c278410f73683957ea6100c8a9d0a8dbe434c49663689255 \ + --hash=sha256:6b2cd7c29d6ecdf0b780deb587198f13213ac01c430ada6913452fd0c40190fc \ + --hash=sha256:6fde3bbb14e92ce8fcb5c2edfff72e474d0080cadda1c97785bf4822f037a309 \ + --hash=sha256:75561f3df9a906aaa23787e9992b228b1ab69007932dc42070f747103e177ba8 \ + --hash=sha256:779027d3307e1a2b1dc0c03c34df87a470a368a1a0840a9d2908baf2d4067956 \ + --hash=sha256:7b6015da2e707bf632a71772a2dbf0703cff6525732c005ad24987fe86e8ec32 \ + --hash=sha256:7f4f43f2204b56a61448ec2dd061e26fd344c404da99fb19f3458200c5874ba2 \ + --hash=sha256:82cac41a411e07a6f3dc80dfbd33f6be70ea0abd72e99c59310819d09f07d945 \ + --hash=sha256:8a2ef08b27167bcff230ffbfeedd4c4fa6353563d6aaa015d725dd3632fc3de7 \ + --hash=sha256:8d1b7082104d596a3eb012e0549b2634ed15015b569f48879701e9d8db959dbb \ + --hash=sha256:8e06fe6a12241ec1b72c0566c6b28cda714d61965d86569595ad24793d1ab259 \ + --hash=sha256:9141fb0592e55f98fe9ac0f3ce883199b9c13e262e0bf40c5b18cdf926109d16 \ + --hash=sha256:92958ae075c87fef393f835ed02d4fe8d5ee2059a0934c6c447ea3417dfbf0e8 \ + --hash=sha256:958473c9f0bca250590200fd520b75be0dbdbc4a7327dc87a55b6d7dc8d68552 \ + --hash=sha256:9a0d519ff39db887cd73f4e297922786d548f5c05d6b51f4e6754f452a7f4296 \ + --hash=sha256:9d81bf186a453a2757472133b24915768abc7c3964194406ed93e170e16c21cb \ + --hash=sha256:9da82aa4b46973aaf9e03bb4c3d6977004648c8638febfc0f9d237e865761270 \ + --hash=sha256:9ef60dfa73749ef91cb6073be1a3e135f4846ec809cc115f3cbfc6fe283a5584 \ + --hash=sha256:9f912d459e46607ce276128f52bea21ebc3e9a5ccf4cccfef30dd5bddcf47be8 \ + --hash=sha256:a1d9aa156ed52d3446388ba4c2f335e312191d1ca9d1f5762ee983cf23e4ecf6 \ + --hash=sha256:a7fbac18f2c19fc983838a60611e67e3262e36859994c26f2ee85bb268de2355 \ + --hash=sha256:aaf83e9170cb1338922ae42d320699dccbbdca8ffed07faeb0b9257822c26e24 \ + --hash=sha256:ac4452f182243cfab30ba4668ef2de101effaedc30f9faabb06a095a8c90fd16 \ + --hash=sha256:ac7adee6bcf0c6fee495d877edad1540a7e0f5fc208da03ccb64734b43522d7a \ + --hash=sha256:b31f358a70efc143909fb3d75ac6cd3c139cd41339aa8f2a3a0ead8315731f2b \ + --hash=sha256:ba7521e072c53e33c384e78615d0718e645cab3c366ecd3cc8cb732befd94967 \ + --hash=sha256:bc308d79a7e877226f36bdf4e149e3ed398d8277c140be5c1fd892ec41739e6d \ + --hash=sha256:bebb7bc6aeb91cc57e4881b222484c26759ca865794187217c9dcea6c33adae6 \ + --hash=sha256:bfa48a4a2d45a41457f0840c48e579db157a927f4e97acf6e20df8fc521c79de \ + --hash=sha256:c0c955e32afdbfdf6e9ee663d24afb25210152d98c26d22d399712d29a9b976b \ + --hash=sha256:c34c022d5ad564f1a5a57a4a89793bd70d7bad428150fb8ff2760b223407cdcf \ + --hash=sha256:c5da802a0d085ad81b0f62828fb55557996c497b2d0b551bbdfeafd6d447892f \ + --hash=sha256:cf654702f144beaa093103841a2ea6910d617d0bb3fccb1d1fd63c54dde2cd49 \ + --hash=sha256:cfcc8feccf63245a22dfdd16e222f1a39771a44b870beb748117a0e09cbb4a62 \ + --hash=sha256:d02cf8e5af89a9ac8f53c438ddff6d773f62c25c6619b29db96f4aae248177c0 \ + --hash=sha256:d99c1cd9443b19164ec185a7d752f4b4db19c066c136f028991a480720472e23 \ + --hash=sha256:dfa64b89dcb906835e275187569e51aa9d546a444489e97aaf2cc84011565fbe \ + --hash=sha256:e8e154b84a311263e1aca86818c962e1fa9eefdd643d1d5d197fcd2738f88cb9 \ + --hash=sha256:ec108bf25de674781d0a9a935030ba090c78d49def3d60f8724f3fc1e8e75024 \ + --hash=sha256:ed4f3adc1294834955b7e74edd3c6bd1aad5831c007f2d91ea839e76461a5879 \ + --hash=sha256:edd062490537e97ca125bc6c7f2b7331c2b73d21dc304615afe61ad1691e15d5 \ + --hash=sha256:efa1582a397da038e2f2576c9cd49b842f56fde37d84a6b0200ffebc08d82350 \ + --hash=sha256:f017dbfecc172e2d0c37cf9e3d519179d71a7f16094b57430dffc496a098aa17 \ + --hash=sha256:f12912acee1f506f974f58de9fdc2e62eea5667377a7e9156de53241c05fdba8 \ + --hash=sha256:f17d9f21bf2f2f785d74f7b0d407805468b4c173fa3e52c86ec94436b338e74a \ + --hash=sha256:f1da2028cb4e41be55ee797a82d6c1cf589442504244249dfeb32efc608edee7 \ + --hash=sha256:f3bb81d4fe6a5d20650f8c0afcc8f6e1941f6fecdb434f11b874c42467baded0 \ + --hash=sha256:f98f36c6a1bb9a6c8bbec99ad87c8c0e364f34761739b5ea9adf7b48129ae8cf \ + --hash=sha256:fc22d69a1c9cccd560a5c434c0371b2df0f47c309c635a01a913e03bbf183710 \ + --hash=sha256:fe07f8b9c3bb5c5ad1d2c66884253e03800f4189a60eb6acd6119ebaf3eb9894 # via -r src/backend/requirements.in -redis==5.1.1 \ - --hash=sha256:f6c997521fedbae53387307c5d0bf784d9acc28d9f1d058abeac566ec4dbed72 \ - --hash=sha256:f8ea06b7482a668c6475ae202ed8d9bcaa409f6e87fb77ed1043d912afd62e24 +redis==5.2.0 \ + --hash=sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0 \ + --hash=sha256:ae174f2bb3b1bf2b09d54bf3e51fbc1469cf6c10aa03e21141f51969801a7897 # via django-redis referencing==0.35.1 \ --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ @@ -1422,101 +1460,101 @@ referencing==0.35.1 \ # via # jsonschema # jsonschema-specifications -regex==2024.9.11 \ - --hash=sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623 \ - --hash=sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199 \ - --hash=sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664 \ - --hash=sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f \ - --hash=sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca \ - --hash=sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066 \ - --hash=sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca \ - --hash=sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39 \ - --hash=sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d \ - --hash=sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6 \ - --hash=sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35 \ - --hash=sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408 \ - --hash=sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5 \ - --hash=sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a \ - --hash=sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9 \ - --hash=sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92 \ - --hash=sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766 \ - --hash=sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168 \ - --hash=sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca \ - --hash=sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508 \ - --hash=sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df \ - --hash=sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf \ - --hash=sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b \ - --hash=sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4 \ - --hash=sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268 \ - --hash=sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6 \ - --hash=sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c \ - --hash=sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62 \ - --hash=sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231 \ - --hash=sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36 \ - --hash=sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba \ - --hash=sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4 \ - --hash=sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e \ - --hash=sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822 \ - --hash=sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4 \ - --hash=sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d \ - --hash=sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71 \ - --hash=sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50 \ - --hash=sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d \ - --hash=sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad \ - --hash=sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8 \ - --hash=sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8 \ - --hash=sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8 \ - --hash=sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd \ - --hash=sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16 \ - --hash=sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664 \ - --hash=sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a \ - --hash=sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f \ - --hash=sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd \ - --hash=sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a \ - --hash=sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9 \ - --hash=sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199 \ - --hash=sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d \ - --hash=sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963 \ - --hash=sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009 \ - --hash=sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a \ - --hash=sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679 \ - --hash=sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96 \ - --hash=sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42 \ - --hash=sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8 \ - --hash=sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e \ - --hash=sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7 \ - --hash=sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8 \ - --hash=sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802 \ - --hash=sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366 \ - --hash=sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137 \ - --hash=sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784 \ - --hash=sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29 \ - --hash=sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3 \ - --hash=sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771 \ - --hash=sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60 \ - --hash=sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a \ - --hash=sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4 \ - --hash=sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0 \ - --hash=sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84 \ - --hash=sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd \ - --hash=sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1 \ - --hash=sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776 \ - --hash=sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142 \ - --hash=sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89 \ - --hash=sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c \ - --hash=sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8 \ - --hash=sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35 \ - --hash=sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a \ - --hash=sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86 \ - --hash=sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9 \ - --hash=sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64 \ - --hash=sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554 \ - --hash=sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85 \ - --hash=sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb \ - --hash=sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0 \ - --hash=sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8 \ - --hash=sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb \ - --hash=sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919 +regex==2024.11.6 \ + --hash=sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c \ + --hash=sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60 \ + --hash=sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d \ + --hash=sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d \ + --hash=sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67 \ + --hash=sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773 \ + --hash=sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0 \ + --hash=sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef \ + --hash=sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad \ + --hash=sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe \ + --hash=sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3 \ + --hash=sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114 \ + --hash=sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4 \ + --hash=sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39 \ + --hash=sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e \ + --hash=sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3 \ + --hash=sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7 \ + --hash=sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d \ + --hash=sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e \ + --hash=sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a \ + --hash=sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7 \ + --hash=sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f \ + --hash=sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0 \ + --hash=sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54 \ + --hash=sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b \ + --hash=sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c \ + --hash=sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd \ + --hash=sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57 \ + --hash=sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34 \ + --hash=sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d \ + --hash=sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f \ + --hash=sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b \ + --hash=sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519 \ + --hash=sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4 \ + --hash=sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a \ + --hash=sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638 \ + --hash=sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b \ + --hash=sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839 \ + --hash=sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07 \ + --hash=sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf \ + --hash=sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff \ + --hash=sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0 \ + --hash=sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f \ + --hash=sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95 \ + --hash=sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4 \ + --hash=sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e \ + --hash=sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13 \ + --hash=sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519 \ + --hash=sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2 \ + --hash=sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008 \ + --hash=sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9 \ + --hash=sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc \ + --hash=sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48 \ + --hash=sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20 \ + --hash=sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89 \ + --hash=sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e \ + --hash=sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf \ + --hash=sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b \ + --hash=sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd \ + --hash=sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84 \ + --hash=sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29 \ + --hash=sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b \ + --hash=sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3 \ + --hash=sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45 \ + --hash=sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3 \ + --hash=sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983 \ + --hash=sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e \ + --hash=sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7 \ + --hash=sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4 \ + --hash=sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e \ + --hash=sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467 \ + --hash=sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577 \ + --hash=sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001 \ + --hash=sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0 \ + --hash=sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55 \ + --hash=sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9 \ + --hash=sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf \ + --hash=sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6 \ + --hash=sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e \ + --hash=sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde \ + --hash=sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62 \ + --hash=sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df \ + --hash=sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51 \ + --hash=sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5 \ + --hash=sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86 \ + --hash=sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2 \ + --hash=sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2 \ + --hash=sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0 \ + --hash=sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c \ + --hash=sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f \ + --hash=sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6 \ + --hash=sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2 \ + --hash=sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9 \ + --hash=sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91 # via -r src/backend/requirements.in requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ @@ -1524,126 +1562,112 @@ requests==2.32.3 \ # via # coreapi # opentelemetry-exporter-otlp-proto-http -rpds-py==0.20.0 \ - --hash=sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c \ - --hash=sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585 \ - --hash=sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5 \ - --hash=sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6 \ - --hash=sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef \ - --hash=sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2 \ - --hash=sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29 \ - --hash=sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318 \ - --hash=sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b \ - --hash=sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399 \ - --hash=sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739 \ - --hash=sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee \ - --hash=sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174 \ - --hash=sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a \ - --hash=sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344 \ - --hash=sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2 \ - --hash=sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03 \ - --hash=sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5 \ - --hash=sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22 \ - --hash=sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e \ - --hash=sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96 \ - --hash=sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91 \ - --hash=sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752 \ - --hash=sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075 \ - --hash=sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253 \ - --hash=sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee \ - --hash=sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad \ - --hash=sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5 \ - --hash=sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce \ - --hash=sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7 \ - --hash=sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b \ - --hash=sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8 \ - --hash=sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57 \ - --hash=sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3 \ - --hash=sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec \ - --hash=sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209 \ - --hash=sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921 \ - --hash=sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045 \ - --hash=sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074 \ - --hash=sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580 \ - --hash=sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7 \ - --hash=sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5 \ - --hash=sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3 \ - --hash=sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0 \ - --hash=sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24 \ - --hash=sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139 \ - --hash=sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db \ - --hash=sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc \ - --hash=sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789 \ - --hash=sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f \ - --hash=sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2 \ - --hash=sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c \ - --hash=sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232 \ - --hash=sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6 \ - --hash=sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c \ - --hash=sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29 \ - --hash=sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489 \ - --hash=sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94 \ - --hash=sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751 \ - --hash=sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2 \ - --hash=sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda \ - --hash=sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9 \ - --hash=sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51 \ - --hash=sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c \ - --hash=sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8 \ - --hash=sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989 \ - --hash=sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511 \ - --hash=sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1 \ - --hash=sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2 \ - --hash=sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150 \ - --hash=sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c \ - --hash=sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965 \ - --hash=sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f \ - --hash=sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58 \ - --hash=sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b \ - --hash=sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f \ - --hash=sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d \ - --hash=sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821 \ - --hash=sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de \ - --hash=sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121 \ - --hash=sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855 \ - --hash=sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272 \ - --hash=sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60 \ - --hash=sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02 \ - --hash=sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1 \ - --hash=sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140 \ - --hash=sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879 \ - --hash=sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940 \ - --hash=sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364 \ - --hash=sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4 \ - --hash=sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e \ - --hash=sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420 \ - --hash=sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5 \ - --hash=sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24 \ - --hash=sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c \ - --hash=sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf \ - --hash=sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f \ - --hash=sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e \ - --hash=sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab \ - --hash=sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08 \ - --hash=sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92 \ - --hash=sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a \ - --hash=sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8 +rpds-py==0.21.0 \ + --hash=sha256:031819f906bb146561af051c7cef4ba2003d28cff07efacef59da973ff7969ba \ + --hash=sha256:0626238a43152918f9e72ede9a3b6ccc9e299adc8ade0d67c5e142d564c9a83d \ + --hash=sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e \ + --hash=sha256:0a9e0759e7be10109645a9fddaaad0619d58c9bf30a3f248a2ea57a7c417173a \ + --hash=sha256:0c025820b78817db6a76413fff6866790786c38f95ea3f3d3c93dbb73b632202 \ + --hash=sha256:1ff2eba7f6c0cb523d7e9cff0903f2fe1feff8f0b2ceb6bd71c0e20a4dcee271 \ + --hash=sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250 \ + --hash=sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d \ + --hash=sha256:2c51d99c30091f72a3c5d126fad26236c3f75716b8b5e5cf8effb18889ced928 \ + --hash=sha256:2d6129137f43f7fa02d41542ffff4871d4aefa724a5fe38e2c31a4e0fd343fb0 \ + --hash=sha256:30b912c965b2aa76ba5168fd610087bad7fcde47f0a8367ee8f1876086ee6d1d \ + --hash=sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333 \ + --hash=sha256:320c808df533695326610a1b6a0a6e98f033e49de55d7dc36a13c8a30cfa756e \ + --hash=sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a \ + --hash=sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18 \ + --hash=sha256:3b929c2bb6e29ab31f12a1117c39f7e6d6450419ab7464a4ea9b0b417174f044 \ + --hash=sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677 \ + --hash=sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664 \ + --hash=sha256:40c91c6e34cf016fa8e6b59d75e3dbe354830777fcfd74c58b279dceb7975b75 \ + --hash=sha256:4991ca61656e3160cdaca4851151fd3f4a92e9eba5c7a530ab030d6aee96ec89 \ + --hash=sha256:4ab2c2a26d2f69cdf833174f4d9d86118edc781ad9a8fa13970b527bf8236027 \ + --hash=sha256:4e8921a259f54bfbc755c5bbd60c82bb2339ae0324163f32868f63f0ebb873d9 \ + --hash=sha256:4eb2de8a147ffe0626bfdc275fc6563aa7bf4b6db59cf0d44f0ccd6ca625a24e \ + --hash=sha256:5145282a7cd2ac16ea0dc46b82167754d5e103a05614b724457cffe614f25bd8 \ + --hash=sha256:520ed8b99b0bf86a176271f6fe23024323862ac674b1ce5b02a72bfeff3fff44 \ + --hash=sha256:52c041802a6efa625ea18027a0723676a778869481d16803481ef6cc02ea8cb3 \ + --hash=sha256:5555db3e618a77034954b9dc547eae94166391a98eb867905ec8fcbce1308d95 \ + --hash=sha256:58a0e345be4b18e6b8501d3b0aa540dad90caeed814c515e5206bb2ec26736fd \ + --hash=sha256:590ef88db231c9c1eece44dcfefd7515d8bf0d986d64d0caf06a81998a9e8cab \ + --hash=sha256:5afb5efde74c54724e1a01118c6e5c15e54e642c42a1ba588ab1f03544ac8c7a \ + --hash=sha256:688c93b77e468d72579351a84b95f976bd7b3e84aa6686be6497045ba84be560 \ + --hash=sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035 \ + --hash=sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919 \ + --hash=sha256:6dcc4949be728ede49e6244eabd04064336012b37f5c2200e8ec8eb2988b209c \ + --hash=sha256:6f54e7106f0001244a5f4cf810ba8d3f9c542e2730821b16e969d6887b664266 \ + --hash=sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e \ + --hash=sha256:8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592 \ + --hash=sha256:878f6fea96621fda5303a2867887686d7a198d9e0f8a40be100a63f5d60c88c9 \ + --hash=sha256:8a7ff941004d74d55a47f916afc38494bd1cfd4b53c482b77c03147c91ac0ac3 \ + --hash=sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624 \ + --hash=sha256:97ef67d9bbc3e15584c2f3c74bcf064af36336c10d2e21a2131e123ce0f924c9 \ + --hash=sha256:98486337f7b4f3c324ab402e83453e25bb844f44418c066623db88e4c56b7c7b \ + --hash=sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f \ + --hash=sha256:998a8080c4495e4f72132f3d66ff91f5997d799e86cec6ee05342f8f3cda7dca \ + --hash=sha256:9afe42102b40007f588666bc7de82451e10c6788f6f70984629db193849dced1 \ + --hash=sha256:9e20da3957bdf7824afdd4b6eeb29510e83e026473e04952dca565170cd1ecc8 \ + --hash=sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590 \ + --hash=sha256:a429b99337062877d7875e4ff1a51fe788424d522bd64a8c0a20ef3021fdb6ed \ + --hash=sha256:a58ce66847711c4aa2ecfcfaff04cb0327f907fead8945ffc47d9407f41ff952 \ + --hash=sha256:a78d8b634c9df7f8d175451cfeac3810a702ccb85f98ec95797fa98b942cea11 \ + --hash=sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061 \ + --hash=sha256:a8eeec67590e94189f434c6d11c426892e396ae59e4801d17a93ac96b8c02a6c \ + --hash=sha256:aaeb25ccfb9b9014a10eaf70904ebf3f79faaa8e60e99e19eef9f478651b9b74 \ + --hash=sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c \ + --hash=sha256:af04ac89c738e0f0f1b913918024c3eab6e3ace989518ea838807177d38a2e94 \ + --hash=sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c \ + --hash=sha256:b21747f79f360e790525e6f6438c7569ddbfb1b3197b9e65043f25c3c9b489d8 \ + --hash=sha256:b229ce052ddf1a01c67d68166c19cb004fb3612424921b81c46e7ea7ccf7c3bf \ + --hash=sha256:b4de1da871b5c0fd5537b26a6fc6814c3cc05cabe0c941db6e9044ffbb12f04a \ + --hash=sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5 \ + --hash=sha256:b876f2bc27ab5954e2fd88890c071bd0ed18b9c50f6ec3de3c50a5ece612f7a6 \ + --hash=sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5 \ + --hash=sha256:b9b76e2afd585803c53c5b29e992ecd183f68285b62fe2668383a18e74abe7a3 \ + --hash=sha256:c2b2f71c6ad6c2e4fc9ed9401080badd1469fa9889657ec3abea42a3d6b2e1ed \ + --hash=sha256:c3761f62fcfccf0864cc4665b6e7c3f0c626f0380b41b8bd1ce322103fa3ef87 \ + --hash=sha256:c38dbf31c57032667dd5a2f0568ccde66e868e8f78d5a0d27dcc56d70f3fcd3b \ + --hash=sha256:ca9989d5d9b1b300bc18e1801c67b9f6d2c66b8fd9621b36072ed1df2c977f72 \ + --hash=sha256:cbd7504a10b0955ea287114f003b7ad62330c9e65ba012c6223dba646f6ffd05 \ + --hash=sha256:d167e4dbbdac48bd58893c7e446684ad5d425b407f9336e04ab52e8b9194e2ed \ + --hash=sha256:d2132377f9deef0c4db89e65e8bb28644ff75a18df5293e132a8d67748397b9f \ + --hash=sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c \ + --hash=sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153 \ + --hash=sha256:dc5695c321e518d9f03b7ea6abb5ea3af4567766f9852ad1560f501b17588c7b \ + --hash=sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0 \ + --hash=sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d \ + --hash=sha256:e12bb09678f38b7597b8346983d2323a6482dcd59e423d9448108c1be37cac9d \ + --hash=sha256:e168afe6bf6ab7ab46c8c375606298784ecbe3ba31c0980b7dcbb9631dcba97e \ + --hash=sha256:e78868e98f34f34a88e23ee9ccaeeec460e4eaf6db16d51d7a9b883e5e785a5e \ + --hash=sha256:e860f065cc4ea6f256d6f411aba4b1251255366e48e972f8a347cf88077b24fd \ + --hash=sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682 \ + --hash=sha256:ebf64e281a06c904a7636781d2e973d1f0926a5b8b480ac658dc0f556e7779f4 \ + --hash=sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db \ + --hash=sha256:ee1e4fc267b437bb89990b2f2abf6c25765b89b72dd4a11e21934df449e0c976 \ + --hash=sha256:ee4eafd77cc98d355a0d02f263efc0d3ae3ce4a7c24740010a8b4012bbb24937 \ + --hash=sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1 \ + --hash=sha256:f414da5c51bf350e4b7960644617c130140423882305f7574b6cf65a3081cecb \ + --hash=sha256:f71009b0d5e94c0e86533c0b27ed7cacc1239cb51c178fd239c3cfefefb0400a \ + --hash=sha256:f983e4c2f603c95dde63df633eec42955508eefd8d0f0e6d236d31a044c882d7 \ + --hash=sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356 \ + --hash=sha256:fed5dfefdf384d6fe975cc026886aece4f292feaf69d0eeb716cfd3c5a4dd8be # via # jsonschema # referencing -sentry-sdk==2.16.0 \ - --hash=sha256:49139c31ebcd398f4f6396b18910610a0c1602f6e67083240c33019d1f6aa30c \ - --hash=sha256:90f733b32e15dfc1999e6b7aca67a38688a567329de4d6e184154a73f96c6892 +sentry-sdk==2.19.0 \ + --hash=sha256:7b0b3b709dee051337244a09a30dbf6e95afe0d34a1f8b430d45e0982a7c125b \ + --hash=sha256:ee4a4d2ae8bfe3cac012dcf3e4607975904c137e1738116549fc3dbbb6ff0e36 # via # -r src/backend/requirements.in # django-q-sentry -setuptools==75.1.0 \ - --hash=sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2 \ - --hash=sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538 +setuptools==75.6.0 \ + --hash=sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6 \ + --hash=sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d # via # -r src/backend/requirements.in # django-money - # opentelemetry-instrumentation sgmllib3k==1.0.0 \ --hash=sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9 # via feedparser @@ -1651,12 +1675,11 @@ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via - # bleach # html5lib # python-dateutil -sqlparse==0.5.1 \ - --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ - --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e +sqlparse==0.5.2 \ + --hash=sha256:9e37b35e16d1cc652a2545f0997c1deb23ea28fa1f3eefe609eee3063c3b105f \ + --hash=sha256:e99bc85c78160918c3e1d9230834ab8d80fc06c59d03f8db2618f65f65dda55e # via # django # django-sql-utils @@ -1670,16 +1693,16 @@ tablib[html, ods, xls, xlsx, yaml]==3.5.0 \ # via # -r src/backend/requirements.in # django-import-export -tinycss2==1.2.1 \ - --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ - --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 +tinycss2==1.4.0 \ + --hash=sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7 \ + --hash=sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289 # via # bleach # cssselect2 # weasyprint -tomli==2.0.2 \ - --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ - --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed +tomli==2.1.0 \ + --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ + --hash=sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391 # via pip-licenses typing-extensions==4.12.2 \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ @@ -1713,9 +1736,9 @@ wcwidth==0.2.13 \ --hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \ --hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5 # via prettytable -weasyprint==61.2 \ - --hash=sha256:47df6cfeeff8c6c28cf2e4caf837cde17715efe462708ada74baa2eb391b6059 \ - --hash=sha256:76c6dc0e75e09182d5645d92c66ddf86b1b992c9420235b723fb374b584e5bf4 +weasyprint==62.3 \ + --hash=sha256:8d8680d732f7fa0fcbc587692a5a5cb095c3525627066918d6e203cbf42b7fcd \ + --hash=sha256:d31048646ce15084e135b33e334a61f526aa68d2f679fcc109ed0e0f5edaed21 # via # -r src/backend/requirements.in # django-weasyprint @@ -1727,81 +1750,76 @@ webencodings==0.5.1 \ # cssselect2 # html5lib # tinycss2 -whitenoise==6.7.0 \ - --hash=sha256:58c7a6cd811e275a6c91af22e96e87da0b1109e9a53bb7464116ef4c963bf636 \ - --hash=sha256:a1ae85e01fdc9815d12fa33f17765bc132ed2c54fa76daf9e39e879dd93566f6 +whitenoise==6.8.2 \ + --hash=sha256:486bd7267a375fa9650b136daaec156ac572971acc8bf99add90817a530dd1d4 \ + --hash=sha256:df12dce147a043d1956d81d288c6f0044147c6d2ab9726e5772ac50fb45d2280 # via -r src/backend/requirements.in -wrapt==1.16.0 \ - --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \ - --hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \ - --hash=sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09 \ - --hash=sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e \ - --hash=sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca \ - --hash=sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0 \ - --hash=sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb \ - --hash=sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487 \ - --hash=sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40 \ - --hash=sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c \ - --hash=sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060 \ - --hash=sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202 \ - --hash=sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41 \ - --hash=sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9 \ - --hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \ - --hash=sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664 \ - --hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \ - --hash=sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362 \ - --hash=sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00 \ - --hash=sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc \ - --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1 \ - --hash=sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267 \ - --hash=sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956 \ - --hash=sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966 \ - --hash=sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1 \ - --hash=sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228 \ - --hash=sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72 \ - --hash=sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d \ - --hash=sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292 \ - --hash=sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0 \ - --hash=sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0 \ - --hash=sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36 \ - --hash=sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c \ - --hash=sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5 \ - --hash=sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f \ - --hash=sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73 \ - --hash=sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b \ - --hash=sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2 \ - --hash=sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593 \ - --hash=sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39 \ - --hash=sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389 \ - --hash=sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf \ - --hash=sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf \ - --hash=sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89 \ - --hash=sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c \ - --hash=sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c \ - --hash=sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f \ - --hash=sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440 \ - --hash=sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465 \ - --hash=sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136 \ - --hash=sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b \ - --hash=sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8 \ - --hash=sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3 \ - --hash=sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8 \ - --hash=sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6 \ - --hash=sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e \ - --hash=sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f \ - --hash=sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c \ - --hash=sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e \ - --hash=sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8 \ - --hash=sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2 \ - --hash=sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020 \ - --hash=sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35 \ - --hash=sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d \ - --hash=sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3 \ - --hash=sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537 \ - --hash=sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809 \ - --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ - --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ - --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 +wrapt==1.17.0 \ + --hash=sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d \ + --hash=sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301 \ + --hash=sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635 \ + --hash=sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a \ + --hash=sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed \ + --hash=sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721 \ + --hash=sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801 \ + --hash=sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b \ + --hash=sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1 \ + --hash=sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88 \ + --hash=sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8 \ + --hash=sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0 \ + --hash=sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f \ + --hash=sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578 \ + --hash=sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7 \ + --hash=sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045 \ + --hash=sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada \ + --hash=sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d \ + --hash=sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b \ + --hash=sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a \ + --hash=sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977 \ + --hash=sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea \ + --hash=sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346 \ + --hash=sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13 \ + --hash=sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22 \ + --hash=sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339 \ + --hash=sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9 \ + --hash=sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181 \ + --hash=sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c \ + --hash=sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90 \ + --hash=sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a \ + --hash=sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489 \ + --hash=sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f \ + --hash=sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504 \ + --hash=sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea \ + --hash=sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569 \ + --hash=sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4 \ + --hash=sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce \ + --hash=sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab \ + --hash=sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a \ + --hash=sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f \ + --hash=sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c \ + --hash=sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9 \ + --hash=sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf \ + --hash=sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d \ + --hash=sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627 \ + --hash=sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d \ + --hash=sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4 \ + --hash=sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c \ + --hash=sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d \ + --hash=sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad \ + --hash=sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b \ + --hash=sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33 \ + --hash=sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371 \ + --hash=sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1 \ + --hash=sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393 \ + --hash=sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106 \ + --hash=sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df \ + --hash=sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379 \ + --hash=sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451 \ + --hash=sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b \ + --hash=sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575 \ + --hash=sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed \ + --hash=sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb \ + --hash=sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838 # via # deprecated # opentelemetry-instrumentation @@ -1874,70 +1892,80 @@ xmlsec==1.3.14 \ --hash=sha256:e732a75fcb6b84872b168f972fbbf3749baf76308635f14015d1d35ed0c5719c \ --hash=sha256:ed4034939d8566ccdcd3b4e4f23c63fd807fb8763ae5668d59a19e11640a8242 # via python3-saml -zipp==3.20.2 \ - --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ - --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 +zipp==3.21.0 \ + --hash=sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4 \ + --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931 # via importlib-metadata -zopfli==0.2.3 \ - --hash=sha256:0574372283befa5af98fb31407e1fe6822f2f9c437ef69e7fa260e49022d8a65 \ - --hash=sha256:082f030b2b7d6d4597ac517816e499c63b92130aa8f4f74a3788ebaa5770f974 \ - --hash=sha256:08d105a49576a9e629f53a710f0009c4bf0a1d8a3239a74e41d0944f26e28a61 \ - --hash=sha256:09ad5f8d7e0fe1975ca6d9fd5ad61c74233ae277982d3bc8814b599bbeb92f44 \ - --hash=sha256:0fbb6e7fc0da56835167e3c83a45b28e99ba14b671ecb8e51100ad03dfffc3d0 \ - --hash=sha256:13d151d5c83980f384439c87a5511853890182c05d93444f3cb05e5ceed37d82 \ - --hash=sha256:1c5fd29730024f5fb0e2623e3853ca422bd3cf57042389c8e0e771dc47f88084 \ - --hash=sha256:1f25f1bb6440ed90a1d458772fa6ce53632f5fb61e435b12ae6b9b39af98d758 \ - --hash=sha256:2073b07c3ec4fcbc895bb02565a90f9f31373233979f6be398e82eacbd1105f3 \ - --hash=sha256:22b1cfc398a87754730f7e268693c8eb480cb688fd645648fda85614a8b1c08c \ - --hash=sha256:2770cf6b88e9985c79b90fd6d4c15d8dab0caa37c1c3b17773e61ce857eab586 \ - --hash=sha256:27f2b58050f84fa059db7a6ec17d98b388c18f9783551e5f97605f790f25e155 \ - --hash=sha256:2da6f30632cefda8ebe032fdcb69cf062f5a6435af9d32de82ccef320e0261f5 \ - --hash=sha256:31c467a300ba46f55aa0ea958ea388e350eefd039cf15764bf4cd737d5eeb8a6 \ - --hash=sha256:39d8a73bee07cf7f2c73e08508bf788bfdf28a527da353b5d3e2a0ee4aaf770c \ - --hash=sha256:3e4675ca4c7b1215b8a53cec1831cbdb6914f91ea2f183817a06fc7b38e27642 \ - --hash=sha256:40665bf0bacc8b82652a1af4016648dd69f896afa59fc481c1d19a222aa746ea \ - --hash=sha256:40b830244e6458ef982b4a5ebb0f228986d481408bae557a95eeece2c5ede4e6 \ - --hash=sha256:52438999888715a378fc6fe1477ab7813e9e9b58a27a38d2ad7be0e396b1ab2e \ - --hash=sha256:57f93802e5ddb20647747ee4039a2e18a26e91bac4c41d3d75a2b2c97f270549 \ - --hash=sha256:5e52aaab3a93470cf0ff2bb2135a8628dda7b70f675c46f35b6a1b30e8e482f4 \ - --hash=sha256:6020a3533c6c7be09db9e59c2a8f3f894bf5d8e95cc01890d82114c923317c57 \ - --hash=sha256:61a2fcc624e8b038d4fca84ba927dc3f31df53a7284692d46aa44d16fb3f47b2 \ - --hash=sha256:61abe5f11400f9c6b22be578091e28dfb9f1a61efaaeaa2da66138b03ee93072 \ - --hash=sha256:6225bbc33c4f803cdc1e71e3028af96dd0e1ed3cf061780d1bf05648df616a05 \ - --hash=sha256:711d4fde9cb99e1a9158978e9d1624a37cdd170ff057f6340059514fcf38e808 \ - --hash=sha256:72349c78da402e6784bd9c5f4aff5cc7017bd969016ec07b656722f7f29fc975 \ - --hash=sha256:7463b42a2cee33f0a018bf8f1304da2379d6cb8111aa4e04d8f8590d0f1099e1 \ - --hash=sha256:7599ce108386d91a402969cba4f17247e33a594b21cbd662e008414ccb0b4cf7 \ - --hash=sha256:7769f6ca73f37dff92159127bd25b0cc7d81d3feb819d355dc7ac01ad05c673d \ - --hash=sha256:78022777139ac973286219e9e085d9496fb6c935502d93a52bd1bed01dfc2002 \ - --hash=sha256:7bc89b71d1c4677f708cc162f40a4560f78f5f4c6aa6d884b423df7d38e8ba0b \ - --hash=sha256:7ddcbc258bb5c07ebb7f6ee64c46d4e35c39c6abba2b3dfa72c0ea4daf9e65fc \ - --hash=sha256:7ebb4e1b0f102d431830151041777c55700d12afd1e5adb5bcbce72037c1a10e \ - --hash=sha256:81d61eba5a8e221b297a1dd27f1dae2785a14a5524cc1e144da53705cf90d5c4 \ - --hash=sha256:8293062567917201609b28b865289d5ddee55030c779fa9264caae4cc2e00fb3 \ - --hash=sha256:84321886cf3e80e086e0f6f7b765975343aafa61165315bb8db514d0bec2d887 \ - --hash=sha256:92ca61eaa1df774908c173683e23c512189bf791a7ebb49fac61324658cff490 \ - --hash=sha256:975d45745cf6c3e3b61127e0140dcf145fa515f2021f669bd82768937b7bb1fb \ - --hash=sha256:978395a4ce5cc46db29a36cdb80549b564dc7706237abaca5aac328dd5842f65 \ - --hash=sha256:97d2f993142fed4f9c11c1766eb53409efe7298c755cf4599c171bfedcbaddae \ - --hash=sha256:9dcf7af42c11b3cf5d3fbf665799e10f54f66caea2020fe304602df83b9a1a69 \ - --hash=sha256:ad2a98890045d13b0cdc93c1637990c211dc877493469afc61a097a00a70cf22 \ - --hash=sha256:ae890df6e5f1e8fa0697cafd848826decce0ac53e54e5a018fd97775e3a354c0 \ - --hash=sha256:b30a922b9d73f22da2b589b35e594dcc6d144eb38ad890c542f2b92902ba9892 \ - --hash=sha256:c1afe5ba0d957e462afbd3da116ac1a2a6d23e8a94436a95b692c5c324694a16 \ - --hash=sha256:c3c61787a90439cf68f751b2a1ab789b0805876c0cd9b58398adc212d1eeace5 \ - --hash=sha256:c6555293e42e7a9154940bb18613de2abce21a855780baff8a6c372e395c59b3 \ - --hash=sha256:ca9a6df3d11c2f8f0356c141523c4914a2850dd39fc213d968c0272db635eea9 \ - --hash=sha256:d0a8e556916088fadb098ddb6eed034d5c2df3b8fba7f2488e87e8c224002eca \ - --hash=sha256:d40373db61883f6fc8b7040c9196a16f737e3063632afd15e8b3f25e871a30e8 \ - --hash=sha256:dbc9841bedd736041eb5e6982cd92da93bee145745f5422f3795f6f258cdc6ef \ - --hash=sha256:dc59299eda2aaf57f0ee5c4b42ada0b80e3dc4c09c5bdda8ee9ae5cf93fafa9e \ - --hash=sha256:deffa15253a43a597e8ebf82ca1908bd70b3bf899da163b017d49ddd5e12732a \ - --hash=sha256:e4068d4d35b2e63898d22e1b7777d986b8f5d61fe83a77973730ce9cff1b4ba1 \ - --hash=sha256:e5f62ca9a947f09f531c721e2a3f2e0094523436b8eb5df18d71245c1924f89a \ - --hash=sha256:eef08c02295bb99c7fdca380c52e5454fa1c08025fb0bea2c7ae6c0e1e9c034b \ - --hash=sha256:f07997453e7777e19ef0a2445cc1b90e1bb90c623dd77554325932dea6350fee \ - --hash=sha256:f48de4818c10c539fdd01276512043ae4ae738e0301e9cace1dd38f4bcffad6a \ - --hash=sha256:f69b161b4d49e256ab285c6c6ee1cf217fda864a9b175d24fa0a0b8c2de9ff13 \ - --hash=sha256:ff86a2cd6b9864027861a129d6d73231b6d463f0d364ca0fdca4492390357cba +zopfli==0.2.3.post1 \ + --hash=sha256:0aa5f90d6298bda02a95bc8dc8c3c19004d5a4e44bda00b67ca7431d857b4b54 \ + --hash=sha256:0cc20b02a9531559945324c38302fd4ba763311632d0ec8a1a0aa9c10ea363e6 \ + --hash=sha256:1d8cc06605519e82b16df090e17cb3990d1158861b2872c3117f1168777b81e4 \ + --hash=sha256:1f990634fd5c5c8ced8edddd8bd45fab565123b4194d6841e01811292650acae \ + --hash=sha256:2345e713260a350bea0b01a816a469ea356bc2d63d009a0d777691ecbbcf7493 \ + --hash=sha256:2768c877f76c8a0e7519b1c86c93757f3c01492ddde55751e9988afb7eff64e1 \ + --hash=sha256:29ea74e72ffa6e291b8c6f2504ce6c146b4fe990c724c1450eb8e4c27fd31431 \ + --hash=sha256:34a99592f3d9eb6f737616b5bd74b48a589fdb3cb59a01a50d636ea81d6af272 \ + --hash=sha256:3654bfc927bc478b1c3f3ff5056ed7b20a1a37fa108ca503256d0a699c03bbb1 \ + --hash=sha256:3657e416ffb8f31d9d3424af12122bb251befae109f2e271d87d825c92fc5b7b \ + --hash=sha256:37d011e92f7b9622742c905fdbed9920a1d0361df84142807ea2a528419dea7f \ + --hash=sha256:3827170de28faf144992d3d4dcf8f3998fe3c8a6a6f4a08f1d42c2ec6119d2bb \ + --hash=sha256:39e576f93576c5c223b41d9c780bbb91fd6db4babf3223d2a4fe7bf568e2b5a8 \ + --hash=sha256:3a89277ed5f8c0fb2d0b46d669aa0633123aa7381f1f6118c12f15e0fb48f8ca \ + --hash=sha256:3c163911f8bad94b3e1db0a572e7c28ba681a0c91d0002ea1e4fa9264c21ef17 \ + --hash=sha256:3f0197b6aa6eb3086ae9e66d6dd86c4d502b6c68b0ec490496348ae8c05ecaef \ + --hash=sha256:48dba9251060289101343110ab47c0756f66f809bb4d1ddbb6d5c7e7752115c5 \ + --hash=sha256:4915a41375bdee4db749ecd07d985a0486eb688a6619f713b7bf6fbfd145e960 \ + --hash=sha256:4c1226a7e2c7105ac31503a9bb97454743f55d88164d6d46bc138051b77f609b \ + --hash=sha256:4e50ffac74842c1c1018b9b73875a0d0a877c066ab06bf7cccbaa84af97e754f \ + --hash=sha256:518f1f4ed35dd69ce06b552f84e6d081f07c552b4c661c5312d950a0b764a58a \ + --hash=sha256:5aad740b4d4fcbaaae4887823925166ffd062db3b248b3f432198fc287381d1a \ + --hash=sha256:5f272186e03ad55e7af09ab78055535c201b1a0bcc2944edb1768298d9c483a4 \ + --hash=sha256:5fcfc0dc2761e4fcc15ad5d273b4d58c2e8e059d3214a7390d4d3c8e2aee644e \ + --hash=sha256:60db20f06c3d4c5934b16cfa62a2cc5c3f0686bffe0071ed7804d3c31ab1a04e \ + --hash=sha256:615a8ac9dda265e9cc38b2a76c3142e4a9f30fea4a79c85f670850783bc6feb4 \ + --hash=sha256:6482db9876c68faac2d20a96b566ffbf65ddaadd97b222e4e73641f4f8722fc4 \ + --hash=sha256:6617fb10f9e4393b331941861d73afb119cd847e88e4974bdbe8068ceef3f73f \ + --hash=sha256:676919fba7311125244eb0c4393679ac5fe856e5864a15d122bd815205369fa0 \ + --hash=sha256:6c2d2bc8129707e34c51f9352c4636ca313b52350bbb7e04637c46c1818a2a70 \ + --hash=sha256:71390dbd3fbf6ebea9a5d85ffed8c26ee1453ee09248e9b88486e30e0397b775 \ + --hash=sha256:716cdbfc57bfd3d3e31a58e6246e8190e6849b7dbb7c4ce39ef8bbf0edb8f6d5 \ + --hash=sha256:75a26a2307b10745a83b660c404416e984ee6fca515ec7f0765f69af3ce08072 \ + --hash=sha256:7be5cc6732eb7b4df17305d8a7b293223f934a31783a874a01164703bc1be6cd \ + --hash=sha256:7cce242b5df12b2b172489daf19c32e5577dd2fac659eb4b17f6a6efb446fd5c \ + --hash=sha256:81c341d9bb87a6dbbb0d45d6e272aca80c7c97b4b210f9b6e233bf8b87242f29 \ + --hash=sha256:89899641d4de97dbad8e0cde690040d078b6aea04066dacaab98e0b5a23573f2 \ + --hash=sha256:8d5ab297d660b75c159190ce6d73035502310e40fd35170aed7d1a1aea7ddd65 \ + --hash=sha256:8fbe5bcf10d01aab3513550f284c09fef32f342b36f56bfae2120a9c4d12c130 \ + --hash=sha256:91a2327a4d7e77471fa4fbb26991c6de4a738c6fc6a33e09bb25f56a870a4b7b \ + --hash=sha256:95a260cafd56b8fffa679918937401c80bb38e1681c448b988022e4c3610965d \ + --hash=sha256:96484dc0f48be1c5d7ae9f38ed1ce41e3675fd506b27c11a6607f14b49101e99 \ + --hash=sha256:9a6aec38a989bad7ddd1ef53f1265699e49e294d08231b5313d61293f3cd6237 \ + --hash=sha256:9ba214f4f45bec195ee8559651154d3ac2932470b9d91c5715fc29c013349f8c \ + --hash=sha256:9f4a7ec2770e6af05f5a02733fd3900f30a9cd58e5d6d3727e14c5bcd6e7d587 \ + --hash=sha256:a1cf720896d2ce998bc8e051d4b4ce0d8bec007aab6243102e8e1d22a0b2fb3f \ + --hash=sha256:a241a68581d34d67b40c425cce3d1fd211c092f99d9250947824ccba9f491949 \ + --hash=sha256:a53b18797cdef27e019db595d66c4b077325afe2fd62145953275f53d84ce40c \ + --hash=sha256:a82fc2dbebe6eb908b9c665e71496f8525c1bc4d2e3a7a7722ef2b128b6227c8 \ + --hash=sha256:a86eb88e06bd87e1fff31dac878965c26b0c26db59ddcf78bb0379a954b120de \ + --hash=sha256:aa588b21044f8a74e423d8c8a4c7fc9988501878aacced793467010039c50734 \ + --hash=sha256:b05296e8bc88c92e2b21e0a9bae4740c1551ee613c1d93a51fd28a7a0b2b6fbb \ + --hash=sha256:b0ec13f352ea5ae0fc91f98a48540512eed0767d0ec4f7f3cb92d92797983d18 \ + --hash=sha256:b3df42f52502438ee973042cc551877d24619fa1cd38ef7b7e9ac74200daca8b \ + --hash=sha256:b78008a69300d929ca2efeffec951b64a312e9a811e265ea4a907ab546d79fa6 \ + --hash=sha256:b9026a21b6d41eb0e2e63f5bc1242c3fcc43ecb770963cda99a4307863dac12e \ + --hash=sha256:bbe429fc50686bb2a2608a30843e36fbaa123462a5284f136c7d9e0145220bfd \ + --hash=sha256:bfa1eb759e07d8b7aa7a310a2bc535e127ee70addf90dc8d4b946b593c3e51a8 \ + --hash=sha256:c1e0ed5d84ffa2d677cc9582fc01e61dab2e7ef8b8996e055f0a76167b1b94df \ + --hash=sha256:c4278d1873ce6e803e5d4f8d702fd3026bd67fca744aa98881324d1157ddf748 \ + --hash=sha256:cac2b37ab21c2b36a10b685b1893ebd6b0f83ae26004838ac817680881576567 \ + --hash=sha256:cbe6df25807227519debd1a57ab236f5f6bad441500e85b13903e51f93a43214 \ + --hash=sha256:cd2c002f160502608dcc822ed2441a0f4509c52e86fcfd1a09e937278ed1ca14 \ + --hash=sha256:e0137dd64a493ba6a4be37405cfd6febe650a98cc1e9dca8f6b8c63b1db11b41 \ + --hash=sha256:e63d558847166543c2c9789e6f985400a520b7eacc4b99181668b2c3aeadd352 \ + --hash=sha256:eb45a34f23da4f8bc712b6376ca5396914b0b7c09adbb001dad964eb7f3132f8 \ + --hash=sha256:ecb7572df5372abce8073df078207d9d1749f20b8b136089916a4a0868d56051 \ + --hash=sha256:f12000a6accdd4bf0a3fa6eaa1b1c7a7bc80af0a2edf3f89d770d3dcce1d0e22 \ + --hash=sha256:f7d69c1a7168ad0e9cb864e8663acb232986a0c9c9cb9801f56bf6214f53a54d \ + --hash=sha256:f815fcc2b2a457977724bad97fb4854022980f51ce7b136925e336b530545ae1 \ + --hash=sha256:fc39f5c27f962ec8660d8d20c24762431131b5d8c672b44b0a54cf2b5bcde9b9 # via fonttools From 708af682e74b409bdd207184e18c55de41f1df21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 09:25:29 +1100 Subject: [PATCH 11/19] Bump the dependencies group across 1 directory with 2 updates (#8558) * Bump the dependencies group across 1 directory with 2 updates Bumps the dependencies group with 2 updates in the /docs directory: [mkdocs-include-markdown-plugin](https://github.com/mondeja/mkdocs-include-markdown-plugin) and [mkdocs-material](https://github.com/squidfunk/mkdocs-material). Updates `mkdocs-include-markdown-plugin` from 7.0.1 to 7.1.1 - [Release notes](https://github.com/mondeja/mkdocs-include-markdown-plugin/releases) - [Commits](https://github.com/mondeja/mkdocs-include-markdown-plugin/compare/v7.0.1...v7.1.1) Updates `mkdocs-material` from 9.5.44 to 9.5.46 - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.44...9.5.46) --- updated-dependencies: - dependency-name: mkdocs-include-markdown-plugin dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies ... Signed-off-by: dependabot[bot] * fix req --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthias Mair --- docs/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 3f174c168c..c79a3ddbbc 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -311,17 +311,17 @@ mkdocs-git-revision-date-localized-plugin==1.3.0 \ --hash=sha256:439e2f14582204050a664c258861c325064d97cdc848c541e48bb034a6c4d0cb \ --hash=sha256:c99377ee119372d57a9e47cff4e68f04cce634a74831c06bc89b33e456e840a1 # via -r docs/requirements.in -mkdocs-include-markdown-plugin==7.0.1 \ - --hash=sha256:4abd341cb1c5eac60ddd1a21540fdff714f1acc99e3b26f37641db60cd175a8d \ - --hash=sha256:d619c206109dab4bab281e2d29b645838d55b0576c761b1fbb17e6bff1170206 +mkdocs-include-markdown-plugin==7.1.1 \ + --hash=sha256:046a452dea2796e93f1385a1db106209a18bb9417162063ffe0a432a97c9b837 \ + --hash=sha256:3ca17da4d5d77cfa5f4da564e65dc74ee2aa6a7368119db23d650fb24d95fce9 # via -r docs/requirements.in mkdocs-macros-plugin==1.3.7 \ --hash=sha256:02432033a5b77fb247d6ec7924e72fc4ceec264165b1644ab8d0dc159c22ce59 \ --hash=sha256:17c7fd1a49b94defcdb502fd453d17a1e730f8836523379d21292eb2be4cb523 # via -r docs/requirements.in -mkdocs-material==9.5.44 \ - --hash=sha256:47015f9c167d58a5ff5e682da37441fc4d66a1c79334bfc08d774763cacf69ca \ - --hash=sha256:f3a6c968e524166b3f3ed1fb97d3ed3e0091183b0545cedf7156a2a6804c56c0 +mkdocs-material==9.5.46 \ + --hash=sha256:98f0a2039c62e551a68aad0791a8d41324ff90c03a6e6cea381a384b84908b83 \ + --hash=sha256:ae2043f4238e572f9a40e0b577f50400d6fc31e2fef8ea141800aebf3bd273d7 # via -r docs/requirements.in mkdocs-material-extensions==1.3.1 \ --hash=sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443 \ From 86c4a67bf36a4279712f86ef6b49641e491dc8d7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 26 Nov 2024 20:29:07 +1100 Subject: [PATCH 12/19] Add location when creating multiple serials (#8564) --- src/backend/InvenTree/build/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/InvenTree/build/models.py b/src/backend/InvenTree/build/models.py index f5530f074d..fadf460d5c 100644 --- a/src/backend/InvenTree/build/models.py +++ b/src/backend/InvenTree/build/models.py @@ -871,6 +871,7 @@ class Build( part=self.part, build=self, batch=batch, + location=location, is_building=True ) From 7b1b476851ceaa487c9d47cd0045157140bd5610 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 26 Nov 2024 20:29:19 +1100 Subject: [PATCH 13/19] Handle pre-rendering when classic frontend is disabled (#8563) --- .../InvenTree/InvenTree/management/commands/prerender.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/backend/InvenTree/InvenTree/management/commands/prerender.py b/src/backend/InvenTree/InvenTree/management/commands/prerender.py index aa752e4e1d..55cf5a27ad 100644 --- a/src/backend/InvenTree/InvenTree/management/commands/prerender.py +++ b/src/backend/InvenTree/InvenTree/management/commands/prerender.py @@ -1,5 +1,6 @@ """Custom management command to prerender files.""" +import logging import os from django.conf import settings @@ -9,6 +10,8 @@ from django.template.loader import render_to_string from django.utils.module_loading import import_string from django.utils.translation import override as lang_over +logger = logging.getLogger('inventree') + def render_file(file_name, source, target, locales, ctx): """Renders a file into all provided locales.""" @@ -31,6 +34,10 @@ class Command(BaseCommand): def handle(self, *args, **kwargs): """Django command to prerender files.""" + if not settings.ENABLE_CLASSIC_FRONTEND: + logger.info('Classic frontend is disabled. Skipping prerendering.') + return + # static directories LC_DIR = settings.LOCALE_PATHS[0] SOURCE_DIR = settings.STATICFILES_I18_SRC From 9d2ca5e61749c5178546de677031ea9a9e38051c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 26 Nov 2024 20:29:37 +1100 Subject: [PATCH 14/19] Set null location on stock item: (#8565) - When consumed by a build order - When shipped to a customer --- src/backend/InvenTree/build/models.py | 1 + src/backend/InvenTree/stock/models.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/backend/InvenTree/build/models.py b/src/backend/InvenTree/build/models.py index fadf460d5c..b397c301bf 100644 --- a/src/backend/InvenTree/build/models.py +++ b/src/backend/InvenTree/build/models.py @@ -1750,6 +1750,7 @@ class BuildItem(InvenTree.models.InvenTreeMetadataModel): else: # Mark the item as "consumed" by the build order item.consumed_by = self.build + item.location = None item.save(add_note=False) item.add_tracking_entry( diff --git a/src/backend/InvenTree/stock/models.py b/src/backend/InvenTree/stock/models.py index a89051fdeb..b414b8592e 100644 --- a/src/backend/InvenTree/stock/models.py +++ b/src/backend/InvenTree/stock/models.py @@ -1403,6 +1403,7 @@ class StockItem( # Assign the other stock item into this one stock_item.belongs_to = self stock_item.consumed_by = build + stock_item.location = None stock_item.save(add_note=False) deltas = {'stockitem': self.pk} From 368f3b7bd42a07594cb881dd06cd0dde445df6fb Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 26 Nov 2024 20:29:51 +1100 Subject: [PATCH 15/19] Remove regex dependency (#8547) * Remove regex from requirements file * Fix order of operations - Remove hidden chars before removing HTML tags * Remove requirement for regex package * Additional unit tests * Remove debug msg * Fix for newline removal * Fix variable shadowing * Defer import of PIL.Image --- src/backend/InvenTree/InvenTree/helpers.py | 39 ++++----- src/backend/InvenTree/InvenTree/mixins.py | 8 +- src/backend/InvenTree/part/test_api.py | 9 ++ src/backend/requirements.in | 1 - src/backend/requirements.txt | 96 ---------------------- 5 files changed, 31 insertions(+), 122 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/helpers.py b/src/backend/InvenTree/InvenTree/helpers.py index 94d9952191..21d20f98ad 100644 --- a/src/backend/InvenTree/InvenTree/helpers.py +++ b/src/backend/InvenTree/InvenTree/helpers.py @@ -23,10 +23,8 @@ from django.utils.translation import gettext_lazy as _ import bleach import pytz -import regex from bleach import clean from djmoney.money import Money -from PIL import Image from common.currency import currency_code_default @@ -140,6 +138,8 @@ def getStaticUrl(filename): def TestIfImage(img): """Test if an image file is indeed an image.""" + from PIL import Image + try: Image.open(img).verify() return True @@ -781,6 +781,8 @@ def strip_html_tags(value: str, raise_error=True, field_name=None): If raise_error is True, a ValidationError will be thrown if HTML tags are detected """ + value = str(value).strip() + cleaned = clean(value, strip=True, tags=[], attributes=[]) # Add escaped characters back in @@ -792,39 +794,32 @@ def strip_html_tags(value: str, raise_error=True, field_name=None): # If the length changed, it means that HTML tags were removed! if len(cleaned) != len(value) and raise_error: field = field_name or 'non_field_errors' - raise ValidationError({field: [_('Remove HTML tags from this value')]}) return cleaned -def remove_non_printable_characters( - value: str, remove_newline=True, remove_ascii=True, remove_unicode=True -): +def remove_non_printable_characters(value: str, remove_newline=True) -> str: """Remove non-printable / control characters from the provided string.""" cleaned = value - if remove_ascii: - # Remove ASCII control characters - # Note that we do not sub out 0x0A (\n) here, it is done separately below - cleaned = regex.sub('[\x00-\x09]+', '', cleaned) - cleaned = regex.sub('[\x0b-\x1f\x7f]+', '', cleaned) + # Remove ASCII control characters + # Note that we do not sub out 0x0A (\n) here, it is done separately below + regex = re.compile(r'[\u0000-\u0009\u000B-\u001F\u007F-\u009F]') + cleaned = regex.sub('', cleaned) + + # Remove Unicode control characters + regex = re.compile(r'[\u200E\u200F\u202A-\u202E]') + cleaned = regex.sub('', cleaned) if remove_newline: - cleaned = regex.sub('[\x0a]+', '', cleaned) - - if remove_unicode: - # Remove Unicode control characters - if remove_newline: - cleaned = regex.sub(r'[^\P{C}]+', '', cleaned) - else: - # Use 'negative-lookahead' to exclude newline character - cleaned = regex.sub('(?![\x0a])[^\\P{C}]+', '', cleaned) + regex = re.compile(r'[\x0A]') + cleaned = regex.sub('', cleaned) return cleaned -def clean_markdown(value: str): +def clean_markdown(value: str) -> str: """Clean a markdown string. This function will remove javascript and other potentially harmful content from the markdown string. @@ -883,7 +878,7 @@ def clean_markdown(value: str): return value -def hash_barcode(barcode_data): +def hash_barcode(barcode_data: str) -> str: """Calculate a 'unique' hash for a barcode string. This hash is used for comparison / lookup. diff --git a/src/backend/InvenTree/InvenTree/mixins.py b/src/backend/InvenTree/InvenTree/mixins.py index ec4fa11f59..3a44975566 100644 --- a/src/backend/InvenTree/InvenTree/mixins.py +++ b/src/backend/InvenTree/InvenTree/mixins.py @@ -57,7 +57,7 @@ class CleanMixin: Ref: https://github.com/mozilla/bleach/issues/192 """ - cleaned = strip_html_tags(data, field_name=field) + cleaned = data # By default, newline characters are removed remove_newline = True @@ -66,13 +66,13 @@ class CleanMixin: try: if hasattr(self, 'serializer_class'): model = self.serializer_class.Meta.model - field = model._meta.get_field(field) + field_base = model._meta.get_field(field) # The following field types allow newline characters allow_newline = [(InvenTreeNotesField, True)] for field_type in allow_newline: - if issubclass(type(field), field_type[0]): + if issubclass(type(field_base), field_type[0]): remove_newline = False is_markdown = field_type[1] break @@ -86,6 +86,8 @@ class CleanMixin: cleaned, remove_newline=remove_newline ) + cleaned = strip_html_tags(cleaned, field_name=field) + if is_markdown: cleaned = clean_markdown(cleaned) diff --git a/src/backend/InvenTree/part/test_api.py b/src/backend/InvenTree/part/test_api.py index 5c74ba7674..bd99f1186b 100644 --- a/src/backend/InvenTree/part/test_api.py +++ b/src/backend/InvenTree/part/test_api.py @@ -281,6 +281,15 @@ class PartCategoryAPITest(InvenTreeAPITestCase): 'A\t part\t category\t', 'A pa\rrt cat\r\r\regory', 'A part\u200e catego\u200fry\u202e', + 'A\u0000 part\u0000 category', + 'A part\u0007 category', + 'A\u001f part category', + 'A part\u007f category', + '\u0001A part category', + 'A part\u0085 category', + 'A part category\u200e', + 'A part cat\u200fegory', + 'A\u0006 part\u007f categ\nory\r', ] for val in values: diff --git a/src/backend/requirements.in b/src/backend/requirements.in index 1cf6f5f347..bb57430473 100644 --- a/src/backend/requirements.in +++ b/src/backend/requirements.in @@ -48,7 +48,6 @@ python-dotenv # Environment variable management pyyaml>=6.0.1 # YAML parsing qrcode[pil] # QR code generator rapidfuzz # Fuzzy string matching -regex # Advanced regular expressions sentry-sdk # Error reporting (optional) setuptools # Standard dependency tablib[xls,xlsx,yaml] # Support for XLS and XLSX formats diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt index 6794b927c5..8b46690864 100644 --- a/src/backend/requirements.txt +++ b/src/backend/requirements.txt @@ -1460,102 +1460,6 @@ referencing==0.35.1 \ # via # jsonschema # jsonschema-specifications -regex==2024.11.6 \ - --hash=sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c \ - --hash=sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60 \ - --hash=sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d \ - --hash=sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d \ - --hash=sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67 \ - --hash=sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773 \ - --hash=sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0 \ - --hash=sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef \ - --hash=sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad \ - --hash=sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe \ - --hash=sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3 \ - --hash=sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114 \ - --hash=sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4 \ - --hash=sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39 \ - --hash=sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e \ - --hash=sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3 \ - --hash=sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7 \ - --hash=sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d \ - --hash=sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e \ - --hash=sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a \ - --hash=sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7 \ - --hash=sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f \ - --hash=sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0 \ - --hash=sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54 \ - --hash=sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b \ - --hash=sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c \ - --hash=sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd \ - --hash=sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57 \ - --hash=sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34 \ - --hash=sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d \ - --hash=sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f \ - --hash=sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b \ - --hash=sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519 \ - --hash=sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4 \ - --hash=sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a \ - --hash=sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638 \ - --hash=sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b \ - --hash=sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839 \ - --hash=sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07 \ - --hash=sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf \ - --hash=sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff \ - --hash=sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0 \ - --hash=sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f \ - --hash=sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95 \ - --hash=sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4 \ - --hash=sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e \ - --hash=sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13 \ - --hash=sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519 \ - --hash=sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2 \ - --hash=sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008 \ - --hash=sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9 \ - --hash=sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc \ - --hash=sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48 \ - --hash=sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20 \ - --hash=sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89 \ - --hash=sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e \ - --hash=sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf \ - --hash=sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b \ - --hash=sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd \ - --hash=sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84 \ - --hash=sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29 \ - --hash=sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b \ - --hash=sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3 \ - --hash=sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45 \ - --hash=sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3 \ - --hash=sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983 \ - --hash=sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e \ - --hash=sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7 \ - --hash=sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4 \ - --hash=sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e \ - --hash=sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467 \ - --hash=sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577 \ - --hash=sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001 \ - --hash=sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0 \ - --hash=sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55 \ - --hash=sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9 \ - --hash=sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf \ - --hash=sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6 \ - --hash=sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e \ - --hash=sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde \ - --hash=sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62 \ - --hash=sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df \ - --hash=sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51 \ - --hash=sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5 \ - --hash=sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86 \ - --hash=sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2 \ - --hash=sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2 \ - --hash=sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0 \ - --hash=sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c \ - --hash=sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f \ - --hash=sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6 \ - --hash=sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2 \ - --hash=sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9 \ - --hash=sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91 - # via -r src/backend/requirements.in requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 From 20fb1250f811259bb9d5675b5815e528bf9411bc Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 27 Nov 2024 07:51:27 +1100 Subject: [PATCH 16/19] Add new report filters for accessing database tables (#8560) * Add new report filters for accessing database tables * Simplify * Handle exception * Add docs * Update docstrings --- docs/docs/report/helpers.md | 72 +++++++++++++++++++ .../InvenTree/report/templatetags/report.py | 46 ++++++++++++ 2 files changed, 118 insertions(+) diff --git a/docs/docs/report/helpers.md b/docs/docs/report/helpers.md index 125d021016..b235005078 100644 --- a/docs/docs/report/helpers.md +++ b/docs/docs/report/helpers.md @@ -78,6 +78,78 @@ To return an element corresponding to a certain key in a container which support {% endraw %} ``` +## Database Helpers + +A number of helper functions are available for accessing database objects: + +### filter_queryset + +The `filter_queryset` function allows for arbitrary filtering of the provided querysert. It takes a queryset and a list of filter arguments, and returns a filtered queryset. + + + +::: report.templatetags.report.filter_queryset + options: + show_docstring_description: false + show_source: False + +!!! info "Provided QuerySet" + The provided queryset must be a valid Django queryset object, which is already available in the template context. + +!!! warning "Advanced Users" + The `filter_queryset` function is a powerful tool, but it is also easy to misuse. It assumes that the user has a good understanding of Django querysets and the underlying database structure. + +#### Example + +In a report template which has a `PurchaseOrder` object available in its context, fetch any line items which have a received quantity greater than zero: + +```html +{% raw %} +{% load report %} + +{% filter_queryset order.lines.all received__gt=0 as received_lines %} + +

    + {% for line in received_lines %} +
  • {{ line.part.part.full_name }} - {{ line.received }} / {{ line.quantity }}
  • + {% endfor %} +
+ +{% endraw %} +``` + +### filter_db_model + +The `filter_db_model` function allows for filtering of a database model based on a set of filter arguments. It takes a model class and a list of filter arguments, and returns a filtered queryset. + +::: report.templatetags.report.filter_db_model + options: + show_docstring_description: false + show_source: False + +#### Example + +Generate a list of all active customers: + +```html +{% raw %} +{% load report %} + +{% filter_db_model company.company is_customer=True active=True as active_customers %} + +
    + {% for customer in active_customers %} +
  • {{ customer.name }}
  • + {% endfor %} +
+ +{% endraw %} +``` + +### Advanced Database Queries + +More advanced database filtering should be achieved using a [report plugin](../extend/plugins/report.md), and adding custom context data to the report template. + ## Number Formatting ### format_number diff --git a/src/backend/InvenTree/report/templatetags/report.py b/src/backend/InvenTree/report/templatetags/report.py index ef4da60206..7093555014 100644 --- a/src/backend/InvenTree/report/templatetags/report.py +++ b/src/backend/InvenTree/report/templatetags/report.py @@ -8,8 +8,10 @@ from decimal import Decimal from typing import Any, Optional from django import template +from django.apps.registry import apps from django.conf import settings from django.core.exceptions import ValidationError +from django.db.models.query import QuerySet from django.utils.safestring import SafeString, mark_safe from django.utils.translation import gettext_lazy as _ @@ -29,6 +31,50 @@ register = template.Library() logger = logging.getLogger('inventree') +@register.simple_tag() +def filter_queryset(queryset: QuerySet, **kwargs) -> QuerySet: + """Filter a database queryset based on the provided keyword arguments. + + Arguments: + queryset: The queryset to filter + + Keyword Arguments: + field (any): Filter the queryset based on the provided field + + Example: + {% filter_queryset companies is_supplier=True as suppliers %} + """ + return queryset.filter(**kwargs) + + +@register.simple_tag() +def filter_db_model(model_name: str, **kwargs) -> QuerySet: + """Filter a database model based on the provided keyword arguments. + + Arguments: + model_name: The name of the Django model - including app name (e.g. 'part.partcategory') + + Keyword Arguments: + field (any): Filter the queryset based on the provided field + + Example: + {% filter_db_model 'part.partcategory' is_template=True as template_parts %} + """ + app_name, model_name = model_name.split('.') + + try: + model = apps.get_model(app_name, model_name) + except Exception: + return None + + if model is None: + return None + + queryset = model.objects.all() + + return filter_queryset(queryset, **kwargs) + + @register.simple_tag() def getindex(container: list, index: int) -> Any: """Return the value contained at the specified index of the list. From af39189e7e805088bf1180e966feab07f25fcc62 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Wed, 27 Nov 2024 03:30:39 +0100 Subject: [PATCH 17/19] Add SelectionList concept (#8054) * Add SelectionList model, APIs and simple tests * Add managment entries * Add field to serializer * add more tests for parameters * Add support for SelectionList to CUI * Add selection option to PUI * fix display * add PUI admin entries * remove get_api_url * fix modeldict * Add models for meta * Add test for inactive lists * Add locking and testing for locking * ignore unneeded section * Add PUI testing for adding parameter * Add selectionList admin * also allow creating entries * extend tests * force click * and more testing * adapt test? * more assurance? * make test more robust * more retries but shorter runs * Update playwright.config.ts * Add docs * Add note regarding administration * Adapt to https://github.com/inventree/InvenTree/pull/8093 * make help text more descriptive * fix migration * remove unneeded UI entries * add lables and describtions to TableFields * factor out selectionList forms * add key to button * cleanup imports * add editable fields * Add function to add row * fix render warning * remove dead parameter * fix migrations * fix migrations * fix format * autofix * fix migrations * fix create / update loop * fix addition of empty lists * extend tests * adjust changelog entry * fix updating loop * update test name * merge migrations * simplify request * - Add entry count to list - Move parameter table to default accordion * fix test * fix test clearing section --------- Co-authored-by: Oliver Walters --- docs/docs/part/parameter.md | 10 + .../InvenTree/InvenTree/api_version.py | 5 +- src/backend/InvenTree/common/api.py | 78 +++++++ ...lectionlist_selectionlistentry_and_more.py | 191 ++++++++++++++++++ src/backend/InvenTree/common/models.py | 163 +++++++++++++++ src/backend/InvenTree/common/serializers.py | 122 ++++++++++- src/backend/InvenTree/common/tests.py | 161 ++++++++++++++- ...132_partparametertemplate_selectionlist.py | 27 +++ src/backend/InvenTree/part/models.py | 14 ++ src/backend/InvenTree/part/serializers.py | 11 +- .../js/translated/model_renderers.js | 14 ++ .../InvenTree/templates/js/translated/part.js | 14 ++ src/backend/InvenTree/users/models.py | 2 + src/frontend/playwright.config.ts | 4 +- .../components/forms/fields/ApiFormField.tsx | 2 + .../components/forms/fields/TableField.tsx | 33 +++ .../src/components/render/Generic.tsx | 13 ++ .../src/components/render/Instance.tsx | 4 +- .../src/components/render/ModelType.tsx | 6 + src/frontend/src/enums/ApiEndpoints.tsx | 2 + src/frontend/src/enums/ModelType.tsx | 1 + src/frontend/src/forms/PartForms.tsx | 21 +- .../src/forms/selectionListFields.tsx | 117 +++++++++++ .../Index/Settings/AdminCenter/Index.tsx | 8 +- .../AdminCenter/PartParameterPanel.tsx | 29 +++ .../part/PartParameterTemplateTable.tsx | 3 +- .../src/tables/part/SelectionListTable.tsx | 134 ++++++++++++ .../tests/settings/selectionList.spec.ts | 100 +++++++++ 28 files changed, 1278 insertions(+), 11 deletions(-) create mode 100644 src/backend/InvenTree/common/migrations/0032_selectionlist_selectionlistentry_and_more.py create mode 100644 src/backend/InvenTree/part/migrations/0132_partparametertemplate_selectionlist.py create mode 100644 src/frontend/src/forms/selectionListFields.tsx create mode 100644 src/frontend/src/pages/Index/Settings/AdminCenter/PartParameterPanel.tsx create mode 100644 src/frontend/src/tables/part/SelectionListTable.tsx create mode 100644 src/frontend/tests/settings/selectionList.spec.ts diff --git a/docs/docs/part/parameter.md b/docs/docs/part/parameter.md index 1e7028cc0b..01058c1c87 100644 --- a/docs/docs/part/parameter.md +++ b/docs/docs/part/parameter.md @@ -26,6 +26,7 @@ Parameter templates are used to define the different types of parameters which a | Units | Optional units field (*must be a valid [physical unit](#parameter-units)*) | | Choices | A comma-separated list of valid choices for parameter values linked to this template. | | Checkbox | If set, parameters linked to this template can only be assigned values *true* or *false* | +| Selection List | If set, parameters linked to this template can only be assigned values from the linked [selection list](#selection-lists) | ### Create Template @@ -105,3 +106,12 @@ Parameter sorting takes unit conversion into account, meaning that values provid {% with id="sort_by_param_units", url="part/part_sorting_units.png", description="Sort by Parameter Units" %} {% include 'img.html' %} {% endwith %} + +### Selection Lists + +Selection Lists can be used to add a large number of predefined values to a parameter template. This can be useful for parameters which must be selected from a large predefined list of values (e.g. a list of standardised colo codes). Choices on templates are limited to 5000 characters, selection lists can be used to overcome this limitation. + +It is possible that plugins lock selection lists to ensure a known state. + + +Administration of lists can be done through the Part Parameter section in the Admin Center or via the API. diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index f62cf923b4..2d1b4e364b 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,13 +1,16 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 285 +INVENTREE_API_VERSION = 286 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v286 - 2024-11-26 : https://github.com/inventree/InvenTree/pull/8054 + - Adds "SelectionList" and "SelectionListEntry" API endpoints + v285 - 2024-11-25 : https://github.com/inventree/InvenTree/pull/8559 - Adds better description for registration endpoints diff --git a/src/backend/InvenTree/common/api.py b/src/backend/InvenTree/common/api.py index e257c31a2f..ca33b208b6 100644 --- a/src/backend/InvenTree/common/api.py +++ b/src/backend/InvenTree/common/api.py @@ -808,6 +808,82 @@ class IconList(ListAPI): return get_icon_packs().values() +class SelectionListList(ListCreateAPI): + """List view for SelectionList objects.""" + + queryset = common.models.SelectionList.objects.all() + serializer_class = common.serializers.SelectionListSerializer + permission_classes = [permissions.IsAuthenticated] + + def get_queryset(self): + """Override the queryset method to include entry count.""" + return self.serializer_class.annotate_queryset(super().get_queryset()) + + +class SelectionListDetail(RetrieveUpdateDestroyAPI): + """Detail view for a SelectionList object.""" + + queryset = common.models.SelectionList.objects.all() + serializer_class = common.serializers.SelectionListSerializer + permission_classes = [permissions.IsAuthenticated] + + +class EntryMixin: + """Mixin for SelectionEntry views.""" + + queryset = common.models.SelectionListEntry.objects.all() + serializer_class = common.serializers.SelectionEntrySerializer + permission_classes = [permissions.IsAuthenticated] + lookup_url_kwarg = 'entrypk' + + def get_queryset(self): + """Prefetch related fields.""" + pk = self.kwargs.get('pk', None) + queryset = super().get_queryset().filter(list=pk) + queryset = queryset.prefetch_related('list') + return queryset + + +class SelectionEntryList(EntryMixin, ListCreateAPI): + """List view for SelectionEntry objects.""" + + +class SelectionEntryDetail(EntryMixin, RetrieveUpdateDestroyAPI): + """Detail view for a SelectionEntry object.""" + + +selection_urls = [ + path( + '/', + include([ + # Entries + path( + 'entry/', + include([ + path( + '/', + include([ + path( + '', + SelectionEntryDetail.as_view(), + name='api-selectionlistentry-detail', + ) + ]), + ), + path( + '', + SelectionEntryList.as_view(), + name='api-selectionlistentry-list', + ), + ]), + ), + path('', SelectionListDetail.as_view(), name='api-selectionlist-detail'), + ]), + ), + path('', SelectionListList.as_view(), name='api-selectionlist-list'), +] + +# API URL patterns settings_api_urls = [ # User settings path( @@ -1016,6 +1092,8 @@ common_api_urls = [ ), # Icons path('icons/', IconList.as_view(), name='api-icon-list'), + # Selection lists + path('selection/', include(selection_urls)), ] admin_api_urls = [ diff --git a/src/backend/InvenTree/common/migrations/0032_selectionlist_selectionlistentry_and_more.py b/src/backend/InvenTree/common/migrations/0032_selectionlist_selectionlistentry_and_more.py new file mode 100644 index 0000000000..3db86b80b9 --- /dev/null +++ b/src/backend/InvenTree/common/migrations/0032_selectionlist_selectionlistentry_and_more.py @@ -0,0 +1,191 @@ +# Generated by Django 4.2.16 on 2024-11-24 12:41 + +import django.db.models.deletion +from django.db import migrations, models + +import InvenTree.models + + +class Migration(migrations.Migration): + dependencies = [ + ('plugin', '0009_alter_pluginconfig_key'), + ('common', '0031_auto_20241026_0024'), + ] + + operations = [ + migrations.CreateModel( + name='SelectionList', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name='ID', + ), + ), + ( + 'metadata', + models.JSONField( + blank=True, + help_text='JSON metadata field, for use by external plugins', + null=True, + verbose_name='Plugin Metadata', + ), + ), + ( + 'name', + models.CharField( + help_text='Name of the selection list', + max_length=100, + unique=True, + verbose_name='Name', + ), + ), + ( + 'description', + models.CharField( + blank=True, + help_text='Description of the selection list', + max_length=250, + verbose_name='Description', + ), + ), + ( + 'locked', + models.BooleanField( + default=False, + help_text='Is this selection list locked?', + verbose_name='Locked', + ), + ), + ( + 'active', + models.BooleanField( + default=True, + help_text='Can this selection list be used?', + verbose_name='Active', + ), + ), + ( + 'source_string', + models.CharField( + blank=True, + help_text='Optional string identifying the source used for this list', + max_length=1000, + verbose_name='Source String', + ), + ), + ( + 'created', + models.DateTimeField( + auto_now_add=True, + help_text='Date and time that the selection list was created', + verbose_name='Created', + ), + ), + ( + 'last_updated', + models.DateTimeField( + auto_now=True, + help_text='Date and time that the selection list was last updated', + verbose_name='Last Updated', + ), + ), + ], + options={ + 'verbose_name': 'Selection List', + 'verbose_name_plural': 'Selection Lists', + }, + bases=(InvenTree.models.PluginValidationMixin, models.Model), + ), + migrations.CreateModel( + name='SelectionListEntry', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name='ID', + ), + ), + ( + 'value', + models.CharField( + help_text='Value of the selection list entry', + max_length=255, + verbose_name='Value', + ), + ), + ( + 'label', + models.CharField( + help_text='Label for the selection list entry', + max_length=255, + verbose_name='Label', + ), + ), + ( + 'description', + models.CharField( + blank=True, + help_text='Description of the selection list entry', + max_length=250, + verbose_name='Description', + ), + ), + ( + 'active', + models.BooleanField( + default=True, + help_text='Is this selection list entry active?', + verbose_name='Active', + ), + ), + ( + 'list', + models.ForeignKey( + blank=True, + help_text='Selection list to which this entry belongs', + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='entries', + to='common.selectionlist', + verbose_name='Selection List', + ), + ), + ], + options={ + 'verbose_name': 'Selection List Entry', + 'verbose_name_plural': 'Selection List Entries', + 'unique_together': {('list', 'value')}, + }, + ), + migrations.AddField( + model_name='selectionlist', + name='default', + field=models.ForeignKey( + blank=True, + help_text='Default entry for this selection list', + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to='common.selectionlistentry', + verbose_name='Default Entry', + ), + ), + migrations.AddField( + model_name='selectionlist', + name='source_plugin', + field=models.ForeignKey( + blank=True, + help_text='Plugin which provides the selection list', + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to='plugin.pluginconfig', + verbose_name='Source Plugin', + ), + ), + ] diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index fb57bfa67d..71b918f866 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -3508,6 +3508,169 @@ class InvenTreeCustomUserStateModel(models.Model): return super().clean() +class SelectionList(InvenTree.models.MetadataMixin, InvenTree.models.InvenTreeModel): + """Class which represents a list of selectable items for parameters. + + A lists selection options can be either manually defined, or sourced from a plugin. + + Attributes: + name: The name of the selection list + description: A description of the selection list + locked: Is this selection list locked (i.e. cannot be modified)? + active: Is this selection list active? + source_plugin: The plugin which provides the selection list + source_string: The string representation of the selection list + default: The default value for the selection list + created: The date/time that the selection list was created + last_updated: The date/time that the selection list was last updated + """ + + class Meta: + """Meta options for SelectionList.""" + + verbose_name = _('Selection List') + verbose_name_plural = _('Selection Lists') + + name = models.CharField( + max_length=100, + verbose_name=_('Name'), + help_text=_('Name of the selection list'), + unique=True, + ) + + description = models.CharField( + max_length=250, + verbose_name=_('Description'), + help_text=_('Description of the selection list'), + blank=True, + ) + + locked = models.BooleanField( + default=False, + verbose_name=_('Locked'), + help_text=_('Is this selection list locked?'), + ) + + active = models.BooleanField( + default=True, + verbose_name=_('Active'), + help_text=_('Can this selection list be used?'), + ) + + source_plugin = models.ForeignKey( + 'plugin.PluginConfig', + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name=_('Source Plugin'), + help_text=_('Plugin which provides the selection list'), + ) + + source_string = models.CharField( + max_length=1000, + verbose_name=_('Source String'), + help_text=_('Optional string identifying the source used for this list'), + blank=True, + ) + + default = models.ForeignKey( + 'SelectionListEntry', + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name=_('Default Entry'), + help_text=_('Default entry for this selection list'), + ) + + created = models.DateTimeField( + auto_now_add=True, + verbose_name=_('Created'), + help_text=_('Date and time that the selection list was created'), + ) + + last_updated = models.DateTimeField( + auto_now=True, + verbose_name=_('Last Updated'), + help_text=_('Date and time that the selection list was last updated'), + ) + + def __str__(self): + """Return string representation of the selection list.""" + if not self.active: + return f'{self.name} (Inactive)' + return self.name + + @staticmethod + def get_api_url(): + """Return the API URL associated with the SelectionList model.""" + return reverse('api-selectionlist-list') + + def get_choices(self): + """Return the choices for the selection list.""" + choices = self.entries.filter(active=True) + return [c.value for c in choices] + + +class SelectionListEntry(models.Model): + """Class which represents a single entry in a SelectionList. + + Attributes: + list: The SelectionList to which this entry belongs + value: The value of the selection list entry + label: The label for the selection list entry + description: A description of the selection list entry + active: Is this selection list entry active? + """ + + class Meta: + """Meta options for SelectionListEntry.""" + + verbose_name = _('Selection List Entry') + verbose_name_plural = _('Selection List Entries') + unique_together = [['list', 'value']] + + list = models.ForeignKey( + SelectionList, + on_delete=models.CASCADE, + null=True, + blank=True, + related_name='entries', + verbose_name=_('Selection List'), + help_text=_('Selection list to which this entry belongs'), + ) + + value = models.CharField( + max_length=255, + verbose_name=_('Value'), + help_text=_('Value of the selection list entry'), + ) + + label = models.CharField( + max_length=255, + verbose_name=_('Label'), + help_text=_('Label for the selection list entry'), + ) + + description = models.CharField( + max_length=250, + verbose_name=_('Description'), + help_text=_('Description of the selection list entry'), + blank=True, + ) + + active = models.BooleanField( + default=True, + verbose_name=_('Active'), + help_text=_('Is this selection list entry active?'), + ) + + def __str__(self): + """Return string representation of the selection list entry.""" + if not self.active: + return f'{self.label} (Inactive)' + return self.label + + class BarcodeScanResult(InvenTree.models.InvenTreeModel): """Model for storing barcode scans results.""" diff --git a/src/backend/InvenTree/common/serializers.py b/src/backend/InvenTree/common/serializers.py index ed134d2707..23c938d9af 100644 --- a/src/backend/InvenTree/common/serializers.py +++ b/src/backend/InvenTree/common/serializers.py @@ -1,7 +1,7 @@ """JSON serializers for common components.""" from django.contrib.contenttypes.models import ContentType -from django.db.models import OuterRef, Subquery +from django.db.models import Count, OuterRef, Subquery from django.urls import reverse from django.utils.translation import gettext_lazy as _ @@ -638,3 +638,123 @@ class IconPackageSerializer(serializers.Serializer): prefix = serializers.CharField() fonts = serializers.DictField(child=serializers.CharField()) icons = serializers.DictField(child=IconSerializer()) + + +class SelectionEntrySerializer(InvenTreeModelSerializer): + """Serializer for a selection entry.""" + + class Meta: + """Meta options for SelectionEntrySerializer.""" + + model = common_models.SelectionListEntry + fields = '__all__' + + def validate(self, attrs): + """Ensure that the selection list is not locked.""" + ret = super().validate(attrs) + if self.instance and self.instance.list.locked: + raise serializers.ValidationError({'list': _('Selection list is locked')}) + return ret + + +class SelectionListSerializer(InvenTreeModelSerializer): + """Serializer for a selection list.""" + + _choices_validated: dict = {} + + class Meta: + """Meta options for SelectionListSerializer.""" + + model = common_models.SelectionList + fields = [ + 'pk', + 'name', + 'description', + 'active', + 'locked', + 'source_plugin', + 'source_string', + 'default', + 'created', + 'last_updated', + 'choices', + 'entry_count', + ] + + default = SelectionEntrySerializer(read_only=True, many=False) + choices = SelectionEntrySerializer(source='entries', many=True, required=False) + entry_count = serializers.IntegerField(read_only=True) + + @staticmethod + def annotate_queryset(queryset): + """Add count of entries for each selection list.""" + return queryset.annotate(entry_count=Count('entries')) + + def is_valid(self, *, raise_exception=False): + """Validate the selection list. Choices are validated separately.""" + choices = ( + self.initial_data.pop('choices') + if self.initial_data.get('choices') is not None + else [] + ) + + # Validate the choices + _choices_validated = [] + db_entries = ( + {a.id: a for a in self.instance.entries.all()} if self.instance else {} + ) + + for choice in choices: + current_inst = db_entries.get(choice.get('id')) + serializer = SelectionEntrySerializer( + instance=current_inst, + data={'list': current_inst.list.pk if current_inst else None, **choice}, + ) + serializer.is_valid(raise_exception=raise_exception) + _choices_validated.append({ + **serializer.validated_data, + 'id': choice.get('id'), + }) + self._choices_validated = _choices_validated + + return super().is_valid(raise_exception=raise_exception) + + def create(self, validated_data): + """Create a new selection list. Save the choices separately.""" + list_entry = common_models.SelectionList.objects.create(**validated_data) + for choice_data in self._choices_validated: + common_models.SelectionListEntry.objects.create(**{ + **choice_data, + 'list': list_entry, + }) + return list_entry + + def update(self, instance, validated_data): + """Update an existing selection list. Save the choices separately.""" + inst_mapping = {inst.id: inst for inst in instance.entries.all()} + exsising_ids = {a.get('id') for a in self._choices_validated} + + # Perform creations and updates. + ret = [] + for data in self._choices_validated: + list_inst = data.get('list', None) + inst = inst_mapping.get(data.get('id')) + if inst is None: + if list_inst is None: + data['list'] = instance + ret.append(SelectionEntrySerializer().create(data)) + else: + ret.append(SelectionEntrySerializer().update(inst, data)) + + # Perform deletions. + for entry_id in inst_mapping.keys() - exsising_ids: + inst_mapping[entry_id].delete() + + return super().update(instance, validated_data) + + def validate(self, attrs): + """Ensure that the selection list is not locked.""" + ret = super().validate(attrs) + if self.instance and self.instance.locked: + raise serializers.ValidationError({'locked': _('Selection list is locked')}) + return ret diff --git a/src/backend/InvenTree/common/tests.py b/src/backend/InvenTree/common/tests.py index cdf8ae4a59..e07afacb93 100644 --- a/src/backend/InvenTree/common/tests.py +++ b/src/backend/InvenTree/common/tests.py @@ -29,7 +29,7 @@ from InvenTree.unit_test import ( InvenTreeTestCase, PluginMixin, ) -from part.models import Part +from part.models import Part, PartParameterTemplate from plugin import registry from plugin.models import NotificationUserSetting @@ -45,6 +45,8 @@ from .models import ( NotificationEntry, NotificationMessage, ProjectCode, + SelectionList, + SelectionListEntry, WebhookEndpoint, WebhookMessage, ) @@ -434,7 +436,7 @@ class SettingsTest(InvenTreeTestCase): try: InvenTreeSetting.set_setting(key, value, change_user=self.user) - except Exception as exc: + except Exception as exc: # pragma: no cover print(f"test_defaults: Failed to set default value for setting '{key}'") raise exc @@ -1683,6 +1685,161 @@ class CustomStatusTest(TestCase): ) +class SelectionListTest(InvenTreeAPITestCase): + """Tests for the SelectionList and SelectionListEntry model and API endpoints.""" + + fixtures = ['category', 'part', 'location', 'params', 'test_templates'] + + def setUp(self): + """Setup for all tests.""" + super().setUp() + + self.list = SelectionList.objects.create(name='Test List') + self.entry1 = SelectionListEntry.objects.create( + list=self.list, + value='test1', + label='Test Entry', + description='Test Description', + ) + self.entry2 = SelectionListEntry.objects.create( + list=self.list, + value='test2', + label='Test Entry 2', + description='Test Description 2', + active=False, + ) + self.list2 = SelectionList.objects.create(name='Test List 2', active=False) + + # Urls + self.list_url = reverse('api-selectionlist-detail', kwargs={'pk': self.list.pk}) + self.entry_url = reverse( + 'api-selectionlistentry-detail', + kwargs={'entrypk': self.entry1.pk, 'pk': self.list.pk}, + ) + + def test_api(self): + """Test the SelectionList and SelctionListEntry API endpoints.""" + url = reverse('api-selectionlist-list') + response = self.get(url, expected_code=200) + self.assertEqual(len(response.data), 2) + + response = self.get(self.list_url, expected_code=200) + self.assertEqual(response.data['name'], 'Test List') + self.assertEqual(len(response.data['choices']), 2) + self.assertEqual(response.data['choices'][0]['value'], 'test1') + self.assertEqual(response.data['choices'][0]['label'], 'Test Entry') + + response = self.get(self.entry_url, expected_code=200) + self.assertEqual(response.data['value'], 'test1') + self.assertEqual(response.data['label'], 'Test Entry') + self.assertEqual(response.data['description'], 'Test Description') + + def test_api_update(self): + """Test adding and editing via the SelectionList.""" + # Test adding a new list via the API + response = self.post( + reverse('api-selectionlist-list'), + { + 'name': 'New List', + 'active': True, + 'choices': [{'value': '1', 'label': 'Test Entry'}], + }, + expected_code=201, + ) + list_pk = response.data['pk'] + self.assertEqual(response.data['name'], 'New List') + self.assertTrue(response.data['active']) + self.assertEqual(len(response.data['choices']), 1) + self.assertEqual(response.data['choices'][0]['value'], '1') + + # Test editing the list choices via the API (remove and add in same call) + response = self.patch( + reverse('api-selectionlist-detail', kwargs={'pk': list_pk}), + {'choices': [{'value': '2', 'label': 'New Label'}]}, + expected_code=200, + ) + self.assertEqual(response.data['name'], 'New List') + self.assertTrue(response.data['active']) + self.assertEqual(len(response.data['choices']), 1) + self.assertEqual(response.data['choices'][0]['value'], '2') + self.assertEqual(response.data['choices'][0]['label'], 'New Label') + entry_id = response.data['choices'][0]['id'] + + # Test changing an entry via list API + response = self.patch( + reverse('api-selectionlist-detail', kwargs={'pk': list_pk}), + {'choices': [{'id': entry_id, 'value': '2', 'label': 'New Label Text'}]}, + expected_code=200, + ) + self.assertEqual(response.data['name'], 'New List') + self.assertTrue(response.data['active']) + self.assertEqual(len(response.data['choices']), 1) + self.assertEqual(response.data['choices'][0]['value'], '2') + self.assertEqual(response.data['choices'][0]['label'], 'New Label Text') + + def test_api_locked(self): + """Test editing with locked/unlocked list.""" + # Lock list + self.list.locked = True + self.list.save() + response = self.patch(self.entry_url, {'label': 'New Label'}, expected_code=400) + self.assertIn('Selection list is locked', response.data['list']) + response = self.patch(self.list_url, {'name': 'New Name'}, expected_code=400) + self.assertIn('Selection list is locked', response.data['locked']) + + # Unlock the list + self.list.locked = False + self.list.save() + response = self.patch(self.entry_url, {'label': 'New Label'}, expected_code=200) + self.assertEqual(response.data['label'], 'New Label') + response = self.patch(self.list_url, {'name': 'New Name'}, expected_code=200) + self.assertEqual(response.data['name'], 'New Name') + + def test_model_meta(self): + """Test model meta functions.""" + # Models str + self.assertEqual(str(self.list), 'Test List') + self.assertEqual(str(self.list2), 'Test List 2 (Inactive)') + self.assertEqual(str(self.entry1), 'Test Entry') + self.assertEqual(str(self.entry2), 'Test Entry 2 (Inactive)') + + # API urls + self.assertEqual(self.list.get_api_url(), '/api/selection/') + + def test_parameter(self): + """Test the SelectionList parameter.""" + self.assertEqual(self.list.get_choices(), ['test1']) + self.user.is_superuser = True + self.user.save() + + # Add to parameter + part = Part.objects.get(pk=1) + template = PartParameterTemplate.objects.create( + name='test_parameter', units='', selectionlist=self.list + ) + rsp = self.get( + reverse('api-part-parameter-template-detail', kwargs={'pk': template.pk}) + ) + self.assertEqual(rsp.data['name'], 'test_parameter') + self.assertEqual(rsp.data['choices'], '') + + # Add to part + url = reverse('api-part-parameter-list') + response = self.post( + url, + {'part': part.pk, 'template': template.pk, 'data': 70}, + expected_code=400, + ) + self.assertIn('Invalid choice for parameter value', response.data['data']) + + response = self.post( + url, + {'part': part.pk, 'template': template.pk, 'data': self.entry1.value}, + expected_code=201, + ) + self.assertEqual(response.data['data'], self.entry1.value) + + class AdminTest(AdminTestCase): """Tests for the admin interface integration.""" diff --git a/src/backend/InvenTree/part/migrations/0132_partparametertemplate_selectionlist.py b/src/backend/InvenTree/part/migrations/0132_partparametertemplate_selectionlist.py new file mode 100644 index 0000000000..e30ffb34c9 --- /dev/null +++ b/src/backend/InvenTree/part/migrations/0132_partparametertemplate_selectionlist.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.16 on 2024-11-24 12:41 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('common', '0032_selectionlist_selectionlistentry_and_more'), + ('part', '0131_partrelated_note'), + ] + + operations = [ + migrations.AddField( + model_name='partparametertemplate', + name='selectionlist', + field=models.ForeignKey( + blank=True, + help_text='Selection list for this parameter', + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='parameter_templates', + to='common.selectionlist', + verbose_name='Selection List', + ), + ) + ] diff --git a/src/backend/InvenTree/part/models.py b/src/backend/InvenTree/part/models.py index 6aab939864..8b6ae18e1b 100644 --- a/src/backend/InvenTree/part/models.py +++ b/src/backend/InvenTree/part/models.py @@ -3724,6 +3724,7 @@ class PartParameterTemplate(InvenTree.models.InvenTreeMetadataModel): description: Description of the parameter [string] checkbox: Boolean flag to indicate whether the parameter is a checkbox [bool] choices: List of valid choices for the parameter [string] + selectionlist: SelectionList that should be used for choices [selectionlist] """ class Meta: @@ -3805,6 +3806,9 @@ class PartParameterTemplate(InvenTree.models.InvenTreeMetadataModel): def get_choices(self): """Return a list of choices for this parameter template.""" + if self.selectionlist: + return self.selectionlist.get_choices() + if not self.choices: return [] @@ -3845,6 +3849,16 @@ class PartParameterTemplate(InvenTree.models.InvenTreeMetadataModel): blank=True, ) + selectionlist = models.ForeignKey( + common.models.SelectionList, + blank=True, + null=True, + on_delete=models.SET_NULL, + related_name='parameter_templates', + verbose_name=_('Selection List'), + help_text=_('Selection list for this parameter'), + ) + @receiver( post_save, diff --git a/src/backend/InvenTree/part/serializers.py b/src/backend/InvenTree/part/serializers.py index 85badda77d..66001ff930 100644 --- a/src/backend/InvenTree/part/serializers.py +++ b/src/backend/InvenTree/part/serializers.py @@ -316,7 +316,16 @@ class PartParameterTemplateSerializer( """Metaclass defining serializer fields.""" model = PartParameterTemplate - fields = ['pk', 'name', 'units', 'description', 'parts', 'checkbox', 'choices'] + fields = [ + 'pk', + 'name', + 'units', + 'description', + 'parts', + 'checkbox', + 'choices', + 'selectionlist', + ] parts = serializers.IntegerField( read_only=True, diff --git a/src/backend/InvenTree/templates/js/translated/model_renderers.js b/src/backend/InvenTree/templates/js/translated/model_renderers.js index 0b96c9a1ec..e66de80989 100644 --- a/src/backend/InvenTree/templates/js/translated/model_renderers.js +++ b/src/backend/InvenTree/templates/js/translated/model_renderers.js @@ -102,6 +102,8 @@ function getModelRenderer(model) { return renderReportTemplate; case 'pluginconfig': return renderPluginConfig; + case 'selectionlist': + return renderSelectionList; default: // Un-handled model type console.error(`Rendering not implemented for model '${model}'`); @@ -589,3 +591,15 @@ function renderPluginConfig(data, parameters={}) { parameters ); } + +// Render for "SelectionList" model +function renderSelectionList(data, parameters={}) { + + return renderModel( + { + text: data.name, + textSecondary: data.description, + }, + parameters + ); +} diff --git a/src/backend/InvenTree/templates/js/translated/part.js b/src/backend/InvenTree/templates/js/translated/part.js index a065aad924..8aba569efb 100644 --- a/src/backend/InvenTree/templates/js/translated/part.js +++ b/src/backend/InvenTree/templates/js/translated/part.js @@ -1356,6 +1356,19 @@ function partParameterFields(options={}) { display_name: choice, }); }); + } else if (response.selectionlist) { + // Selection list - get choices from the API + inventreeGet(`{% url "api-selectionlist-list" %}${response.selectionlist}/`, {}, { + async: false, + success: function(data) { + data.choices.forEach(function(item) { + choices.push({ + value: item.value, + display_name: item.label, + }); + }); + } + }); } } }); @@ -1576,6 +1589,7 @@ function partParameterTemplateFields() { icon: 'fa-th-list', }, checkbox: {}, + selectionlist: {}, }; } diff --git a/src/backend/InvenTree/users/models.py b/src/backend/InvenTree/users/models.py index c755702a72..161b1c1642 100644 --- a/src/backend/InvenTree/users/models.py +++ b/src/backend/InvenTree/users/models.py @@ -347,6 +347,8 @@ class RuleSet(models.Model): 'common_webhookendpoint', 'common_webhookmessage', 'common_inventreecustomuserstatemodel', + 'common_selectionlistentry', + 'common_selectionlist', 'users_owner', # Third-party tables 'error_report_error', diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 3bdc40fcd4..8b20b1745a 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -5,8 +5,8 @@ export default defineConfig({ fullyParallel: true, timeout: 90000, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 1 : 0, - workers: process.env.CI ? 2 : undefined, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 3 : undefined, reporter: process.env.CI ? [['html', { open: 'never' }], ['github']] : 'list', /* Configure projects for major browsers */ diff --git a/src/frontend/src/components/forms/fields/ApiFormField.tsx b/src/frontend/src/components/forms/fields/ApiFormField.tsx index 8a4426564b..6cc1d9fe52 100644 --- a/src/frontend/src/components/forms/fields/ApiFormField.tsx +++ b/src/frontend/src/components/forms/fields/ApiFormField.tsx @@ -49,6 +49,7 @@ export type ApiFormAdjustFilterType = { * @param onValueChange : Callback function to call when the field value changes * @param adjustFilters : Callback function to adjust the filters for a related field before a query is made * @param adjustValue : Callback function to adjust the value of the field before it is sent to the API + * @param addRow : Callback function to add a new row to a table field * @param onKeyDown : Callback function to get which key was pressed in the form to handle submission on enter */ export type ApiFormFieldType = { @@ -94,6 +95,7 @@ export type ApiFormFieldType = { adjustValue?: (value: any) => any; onValueChange?: (value: any, record?: any) => void; adjustFilters?: (value: ApiFormAdjustFilterType) => any; + addRow?: () => any; headers?: string[]; depends_on?: string[]; }; diff --git a/src/frontend/src/components/forms/fields/TableField.tsx b/src/frontend/src/components/forms/fields/TableField.tsx index e979d0f7e3..6db54e8164 100644 --- a/src/frontend/src/components/forms/fields/TableField.tsx +++ b/src/frontend/src/components/forms/fields/TableField.tsx @@ -6,6 +6,7 @@ import type { FieldValues, UseControllerReturn } from 'react-hook-form'; import { identifierString } from '../../../functions/conversion'; import { InvenTreeIcon } from '../../../functions/icons'; +import { AddItemButton } from '../../buttons/AddItemButton'; import { StandaloneField } from '../StandaloneField'; import type { ApiFormFieldType } from './ApiFormField'; @@ -109,6 +110,17 @@ export function TableField({ field.onChange(val); }; + const fieldDefinition = useMemo(() => { + return { + ...definition, + modelRenderer: undefined, + onValueChange: undefined, + adjustFilters: undefined, + read_only: undefined, + addRow: undefined + }; + }, [definition]); + // Extract errors associated with the current row const rowErrors: any = useCallback( (idx: number) => { @@ -134,6 +146,7 @@ export function TableField({ })} + {value.length > 0 ? ( value.map((item: any, idx: number) => { @@ -170,6 +183,26 @@ export function TableField({ )} + {definition.addRow && ( + + + + { + if (definition.addRow === undefined) return; + const ret = definition.addRow(); + if (ret) { + const val = field.value; + val.push(ret); + field.onChange(val); + } + }} + /> + + + + )} ); } diff --git a/src/frontend/src/components/render/Generic.tsx b/src/frontend/src/components/render/Generic.tsx index 1b5f412e76..a108ef1999 100644 --- a/src/frontend/src/components/render/Generic.tsx +++ b/src/frontend/src/components/render/Generic.tsx @@ -34,3 +34,16 @@ export function RenderImportSession({ }): ReactNode { return instance && ; } + +export function RenderSelectionList({ + instance +}: Readonly): ReactNode { + return ( + instance && ( + + ) + ); +} diff --git a/src/frontend/src/components/render/Instance.tsx b/src/frontend/src/components/render/Instance.tsx index 8e95b604a8..0778809813 100644 --- a/src/frontend/src/components/render/Instance.tsx +++ b/src/frontend/src/components/render/Instance.tsx @@ -20,7 +20,8 @@ import { RenderContentType, RenderError, RenderImportSession, - RenderProjectCode + RenderProjectCode, + RenderSelectionList } from './Generic'; import { ModelInformationDict } from './ModelType'; import { @@ -94,6 +95,7 @@ const RendererLookup: EnumDictionary< [ModelType.labeltemplate]: RenderLabelTemplate, [ModelType.pluginconfig]: RenderPlugin, [ModelType.contenttype]: RenderContentType, + [ModelType.selectionlist]: RenderSelectionList, [ModelType.error]: RenderError }; diff --git a/src/frontend/src/components/render/ModelType.tsx b/src/frontend/src/components/render/ModelType.tsx index ea802ac173..47d358413d 100644 --- a/src/frontend/src/components/render/ModelType.tsx +++ b/src/frontend/src/components/render/ModelType.tsx @@ -286,6 +286,12 @@ export const ModelInformationDict: ModelDict = { api_endpoint: ApiEndpoints.content_type_list, icon: 'list_details' }, + selectionlist: { + label: () => t`Selection List`, + label_multiple: () => t`Selection Lists`, + api_endpoint: ApiEndpoints.selectionlist_list, + icon: 'list_details' + }, error: { label: () => t`Error`, label_multiple: () => t`Errors`, diff --git a/src/frontend/src/enums/ApiEndpoints.tsx b/src/frontend/src/enums/ApiEndpoints.tsx index 8ca5dca0ae..0206dcd55f 100644 --- a/src/frontend/src/enums/ApiEndpoints.tsx +++ b/src/frontend/src/enums/ApiEndpoints.tsx @@ -49,6 +49,8 @@ export enum ApiEndpoints { owner_list = 'user/owner/', content_type_list = 'contenttype/', icons = 'icons/', + selectionlist_list = 'selection/', + selectionlist_detail = 'selection/:id/', // Barcode API endpoints barcode = 'barcode/', diff --git a/src/frontend/src/enums/ModelType.tsx b/src/frontend/src/enums/ModelType.tsx index 1c78bd3e33..84bf7ca60b 100644 --- a/src/frontend/src/enums/ModelType.tsx +++ b/src/frontend/src/enums/ModelType.tsx @@ -33,5 +33,6 @@ export enum ModelType { labeltemplate = 'labeltemplate', pluginconfig = 'pluginconfig', contenttype = 'contenttype', + selectionlist = 'selectionlist', error = 'error' } diff --git a/src/frontend/src/forms/PartForms.tsx b/src/frontend/src/forms/PartForms.tsx index f390168168..ecff565731 100644 --- a/src/frontend/src/forms/PartForms.tsx +++ b/src/frontend/src/forms/PartForms.tsx @@ -2,7 +2,10 @@ import { t } from '@lingui/macro'; import { IconPackages } from '@tabler/icons-react'; import { useMemo, useState } from 'react'; +import { api } from '../App'; import type { ApiFormFieldSet } from '../components/forms/fields/ApiFormField'; +import { ApiEndpoints } from '../enums/ApiEndpoints'; +import { apiUrl } from '../states/ApiState'; import { useGlobalSettingsState } from '../states/SettingsState'; /** @@ -204,7 +207,7 @@ export function usePartParameterFields({ setChoices( _choices.map((choice) => { return { - label: choice.trim(), + display_name: choice.trim(), value: choice.trim() }; }) @@ -214,6 +217,22 @@ export function usePartParameterFields({ setChoices([]); setFieldType('string'); } + } else if (record?.selectionlist) { + api + .get( + apiUrl(ApiEndpoints.selectionlist_detail, record.selectionlist) + ) + .then((res) => { + setChoices( + res.data.choices.map((item: any) => { + return { + value: item.value, + display_name: item.label + }; + }) + ); + setFieldType('choice'); + }); } else { setChoices([]); setFieldType('string'); diff --git a/src/frontend/src/forms/selectionListFields.tsx b/src/frontend/src/forms/selectionListFields.tsx new file mode 100644 index 0000000000..f13de38161 --- /dev/null +++ b/src/frontend/src/forms/selectionListFields.tsx @@ -0,0 +1,117 @@ +import { t } from '@lingui/macro'; +import { Table } from '@mantine/core'; +import { useMemo } from 'react'; + +import RemoveRowButton from '../components/buttons/RemoveRowButton'; +import { StandaloneField } from '../components/forms/StandaloneField'; +import type { + ApiFormFieldSet, + ApiFormFieldType +} from '../components/forms/fields/ApiFormField'; +import type { TableFieldRowProps } from '../components/forms/fields/TableField'; + +function BuildAllocateLineRow({ + props +}: Readonly<{ + props: TableFieldRowProps; +}>) { + const valueField: ApiFormFieldType = useMemo(() => { + return { + field_type: 'string', + name: 'value', + required: true, + value: props.item.value, + onValueChange: (value: any) => { + props.changeFn(props.idx, 'value', value); + } + }; + }, [props]); + + const labelField: ApiFormFieldType = useMemo(() => { + return { + field_type: 'string', + name: 'label', + required: true, + value: props.item.label, + onValueChange: (value: any) => { + props.changeFn(props.idx, 'label', value); + } + }; + }, [props]); + + const descriptionField: ApiFormFieldType = useMemo(() => { + return { + field_type: 'string', + name: 'description', + required: true, + value: props.item.description, + onValueChange: (value: any) => { + props.changeFn(props.idx, 'description', value); + } + }; + }, [props]); + + const activeField: ApiFormFieldType = useMemo(() => { + return { + field_type: 'boolean', + name: 'active', + required: true, + value: props.item.active, + onValueChange: (value: any) => { + props.changeFn(props.idx, 'active', value); + } + }; + }, [props]); + + return ( + + + + + + + + + + + + + + + props.removeFn(props.idx)} /> + + + ); +} + +export function selectionListFields(): ApiFormFieldSet { + return { + name: {}, + description: {}, + active: {}, + locked: {}, + source_plugin: {}, + source_string: {}, + choices: { + label: t`Entries`, + description: t`List of entries to choose from`, + field_type: 'table', + value: [], + headers: [t`Value`, t`Label`, t`Description`, t`Active`], + modelRenderer: (row: TableFieldRowProps) => ( + + ), + addRow: () => { + return { + value: '', + label: '', + description: '', + active: true + }; + } + } + }; +} diff --git a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx index 2b3fe2a7cc..afc959fe14 100644 --- a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx +++ b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx @@ -66,6 +66,8 @@ const MachineManagementPanel = Loadable( lazy(() => import('./MachineManagementPanel')) ); +const PartParameterPanel = Loadable(lazy(() => import('./PartParameterPanel'))); + const ErrorReportTable = Loadable( lazy(() => import('../../../../tables/settings/ErrorTable')) ); @@ -86,6 +88,10 @@ const CustomStateTable = Loadable( lazy(() => import('../../../../tables/settings/CustomStateTable')) ); +const CustomUnitsTable = Loadable( + lazy(() => import('../../../../tables/settings/CustomUnitsTable')) +); + const PartParameterTemplateTable = Loadable( lazy(() => import('../../../../tables/part/PartParameterTemplateTable')) ); @@ -169,7 +175,7 @@ export default function AdminCenter() { name: 'part-parameters', label: t`Part Parameters`, icon: , - content: + content: }, { name: 'category-parameters', diff --git a/src/frontend/src/pages/Index/Settings/AdminCenter/PartParameterPanel.tsx b/src/frontend/src/pages/Index/Settings/AdminCenter/PartParameterPanel.tsx new file mode 100644 index 0000000000..5973eb1502 --- /dev/null +++ b/src/frontend/src/pages/Index/Settings/AdminCenter/PartParameterPanel.tsx @@ -0,0 +1,29 @@ +import { t } from '@lingui/macro'; +import { Accordion } from '@mantine/core'; + +import { StylishText } from '../../../../components/items/StylishText'; +import PartParameterTemplateTable from '../../../../tables/part/PartParameterTemplateTable'; +import SelectionListTable from '../../../../tables/part/SelectionListTable'; + +export default function PartParameterPanel() { + return ( + + + + {t`Part Parameter Template`} + + + + + + + + {t`Selection Lists`} + + + + + + + ); +} diff --git a/src/frontend/src/tables/part/PartParameterTemplateTable.tsx b/src/frontend/src/tables/part/PartParameterTemplateTable.tsx index b77e7c2e10..3a27402ddb 100644 --- a/src/frontend/src/tables/part/PartParameterTemplateTable.tsx +++ b/src/frontend/src/tables/part/PartParameterTemplateTable.tsx @@ -76,7 +76,8 @@ export default function PartParameterTemplateTable() { description: {}, units: {}, choices: {}, - checkbox: {} + checkbox: {}, + selectionlist: {} }; }, []); diff --git a/src/frontend/src/tables/part/SelectionListTable.tsx b/src/frontend/src/tables/part/SelectionListTable.tsx new file mode 100644 index 0000000000..acbbe100e3 --- /dev/null +++ b/src/frontend/src/tables/part/SelectionListTable.tsx @@ -0,0 +1,134 @@ +import { t } from '@lingui/macro'; +import { useCallback, useMemo, useState } from 'react'; + +import { AddItemButton } from '../../components/buttons/AddItemButton'; +import { ApiEndpoints } from '../../enums/ApiEndpoints'; +import { UserRoles } from '../../enums/Roles'; +import { selectionListFields } from '../../forms/selectionListFields'; +import { + useCreateApiFormModal, + useDeleteApiFormModal, + useEditApiFormModal +} from '../../hooks/UseForm'; +import { useTable } from '../../hooks/UseTable'; +import { apiUrl } from '../../states/ApiState'; +import { useUserState } from '../../states/UserState'; +import type { TableColumn } from '../Column'; +import { BooleanColumn } from '../ColumnRenderers'; +import { InvenTreeTable } from '../InvenTreeTable'; +import { type RowAction, RowDeleteAction, RowEditAction } from '../RowActions'; + +/** + * Table for displaying list of selectionlist items + */ +export default function SelectionListTable() { + const table = useTable('selectionlist'); + + const user = useUserState(); + + const columns: TableColumn[] = useMemo(() => { + return [ + { + accessor: 'name', + sortable: true + }, + { + accessor: 'description', + sortable: true + }, + BooleanColumn({ + accessor: 'active' + }), + BooleanColumn({ + accessor: 'locked' + }), + { + accessor: 'source_plugin', + sortable: true + }, + { + accessor: 'source_string', + sortable: true + }, + { + accessor: 'entry_count' + } + ]; + }, []); + + const newSelectionList = useCreateApiFormModal({ + url: ApiEndpoints.selectionlist_list, + title: t`Add Selection List`, + fields: selectionListFields(), + table: table + }); + + const [selectedSelectionList, setSelectedSelectionList] = useState< + number | undefined + >(undefined); + + const editSelectionList = useEditApiFormModal({ + url: ApiEndpoints.selectionlist_list, + pk: selectedSelectionList, + title: t`Edit Selection List`, + fields: selectionListFields(), + table: table + }); + + const deleteSelectionList = useDeleteApiFormModal({ + url: ApiEndpoints.selectionlist_list, + pk: selectedSelectionList, + title: t`Delete Selection List`, + table: table + }); + + const rowActions = useCallback( + (record: any): RowAction[] => { + return [ + RowEditAction({ + hidden: !user.hasChangeRole(UserRoles.admin), + onClick: () => { + setSelectedSelectionList(record.pk); + editSelectionList.open(); + } + }), + RowDeleteAction({ + hidden: !user.hasDeleteRole(UserRoles.admin), + onClick: () => { + setSelectedSelectionList(record.pk); + deleteSelectionList.open(); + } + }) + ]; + }, + [user] + ); + + const tableActions = useMemo(() => { + return [ + newSelectionList.open()} + tooltip={t`Add Selection List`} + /> + ]; + }, []); + + return ( + <> + {newSelectionList.modal} + {editSelectionList.modal} + {deleteSelectionList.modal} + + + ); +} diff --git a/src/frontend/tests/settings/selectionList.spec.ts b/src/frontend/tests/settings/selectionList.spec.ts new file mode 100644 index 0000000000..b7cc316611 --- /dev/null +++ b/src/frontend/tests/settings/selectionList.spec.ts @@ -0,0 +1,100 @@ +import { test } from '../baseFixtures'; +import { baseUrl } from '../defaults'; +import { doQuickLogin } from '../login'; + +test('PUI - Admin - Parameter', async ({ page }) => { + await doQuickLogin(page, 'admin', 'inventree'); + await page.getByRole('button', { name: 'admin' }).click(); + await page.getByRole('menuitem', { name: 'Admin Center' }).click(); + await page.getByRole('tab', { name: 'Part Parameters' }).click(); + + await page.getByRole('button', { name: 'Selection Lists' }).click(); + await page.waitForLoadState('networkidle'); + + // clean old data if exists + await page + .getByRole('cell', { name: 'some list' }) + .waitFor({ timeout: 200 }) + .then(async (cell) => { + await page + .getByRole('cell', { name: 'some list' }) + .locator('..') + .getByLabel('row-action-menu-') + .click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'Delete' }).click(); + }) + .catch(() => {}); + + // clean old data if exists + await page.getByRole('button', { name: 'Part Parameter Template' }).click(); + await page.waitForLoadState('networkidle'); + await page + .getByRole('cell', { name: 'my custom parameter' }) + .waitFor({ timeout: 200 }) + .then(async (cell) => { + await page + .getByRole('cell', { name: 'my custom parameter' }) + .locator('..') + .getByLabel('row-action-menu-') + .click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'Delete' }).click(); + }) + .catch(() => {}); + + // Add selection list + await page.getByRole('button', { name: 'Selection Lists' }).click(); + await page.waitForLoadState('networkidle'); + await page.getByLabel('action-button-add-selection-').waitFor(); + await page.getByLabel('action-button-add-selection-').click(); + await page.getByLabel('text-field-name').fill('some list'); + await page.getByLabel('text-field-description').fill('Listdescription'); + await page.getByRole('button', { name: 'Submit' }).click(); + await page.getByRole('cell', { name: 'some list' }).waitFor(); + await page.waitForTimeout(200); + + // Add parameter + await page.waitForLoadState('networkidle'); + await page.getByRole('button', { name: 'Part Parameter Template' }).click(); + await page.getByLabel('action-button-add-parameter').waitFor(); + await page.getByLabel('action-button-add-parameter').click(); + await page.getByLabel('text-field-name').fill('my custom parameter'); + await page.getByLabel('text-field-description').fill('description'); + await page + .locator('div') + .filter({ hasText: /^Search\.\.\.$/ }) + .nth(2) + .click(); + await page + .getByRole('option', { name: 'some list' }) + .locator('div') + .first() + .click(); + await page.getByRole('button', { name: 'Submit' }).click(); + await page.getByRole('cell', { name: 'my custom parameter' }).click(); + + // Fill parameter + await page.goto(`${baseUrl}/part/104/parameters/`); + await page.getByLabel('Parameters').getByText('Parameters').waitFor(); + await page.waitForLoadState('networkidle'); + await page.getByLabel('action-button-add-parameter').waitFor(); + await page.getByLabel('action-button-add-parameter').click(); + await page.waitForTimeout(200); + await page.getByText('New Part Parameter').waitFor(); + await page + .getByText('Template *Parameter') + .locator('div') + .filter({ hasText: /^Search\.\.\.$/ }) + .nth(2) + .click(); + await page + .getByText('Template *Parameter') + .locator('div') + .filter({ hasText: /^Search\.\.\.$/ }) + .locator('input') + .fill('my custom parameter'); + await page.getByRole('option', { name: 'my custom parameter' }).click(); + await page.getByLabel('choice-field-data').fill('2'); + await page.getByRole('button', { name: 'Submit' }).click(); +}); From 81e87a65e2d576b61fd32500b78df40a6ad438b0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 27 Nov 2024 15:01:07 +1100 Subject: [PATCH 18/19] [PUI] Fix stock actions (#8569) * Fix useAssignStockItems - Only allow "salable" parts * Assign item to customer * Adjust playwright tests --- src/frontend/src/forms/StockForms.tsx | 35 ++++++++++++++----- src/frontend/src/pages/stock/StockDetail.tsx | 18 ++++++++-- .../src/tables/stock/StockItemTable.tsx | 2 +- src/frontend/tests/pages/pui_stock.spec.ts | 2 +- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/frontend/src/forms/StockForms.tsx b/src/frontend/src/forms/StockForms.tsx index 53775e75b3..56218268b5 100644 --- a/src/frontend/src/forms/StockForms.tsx +++ b/src/frontend/src/forms/StockForms.tsx @@ -870,6 +870,7 @@ function stockOperationModal({ endpoint, filters, title, + successMessage, modalFunc = useCreateApiFormModal }: { items?: object; @@ -880,6 +881,7 @@ function stockOperationModal({ fieldGenerator: (items: any[]) => ApiFormFieldSet; endpoint: ApiEndpoints; title: string; + successMessage?: string; modalFunc?: apiModalFunc; }) { const baseParams: any = { @@ -932,12 +934,13 @@ function stockOperationModal({ fields: fields, title: title, size: '80%', + successMessage: successMessage, onFormSuccess: () => refresh() }); } export type StockOperationProps = { - items?: object; + items?: any[]; pk?: number; filters?: any; model: ModelType.stockitem | 'location' | ModelType.part; @@ -949,7 +952,8 @@ export function useAddStockItem(props: StockOperationProps) { ...props, fieldGenerator: stockAddFields, endpoint: ApiEndpoints.stock_add, - title: t`Add Stock` + title: t`Add Stock`, + successMessage: t`Stock added` }); } @@ -958,7 +962,8 @@ export function useRemoveStockItem(props: StockOperationProps) { ...props, fieldGenerator: stockRemoveFields, endpoint: ApiEndpoints.stock_remove, - title: t`Remove Stock` + title: t`Remove Stock`, + successMessage: t`Stock removed` }); } @@ -967,7 +972,8 @@ export function useTransferStockItem(props: StockOperationProps) { ...props, fieldGenerator: stockTransferFields, endpoint: ApiEndpoints.stock_transfer, - title: t`Transfer Stock` + title: t`Transfer Stock`, + successMessage: t`Stock transferred` }); } @@ -976,7 +982,8 @@ export function useCountStockItem(props: StockOperationProps) { ...props, fieldGenerator: stockCountFields, endpoint: ApiEndpoints.stock_count, - title: t`Count Stock` + title: t`Count Stock`, + successMessage: t`Stock counted` }); } @@ -985,7 +992,8 @@ export function useChangeStockStatus(props: StockOperationProps) { ...props, fieldGenerator: stockChangeStatusFields, endpoint: ApiEndpoints.stock_change_status, - title: t`Change Stock Status` + title: t`Change Stock Status`, + successMessage: t`Stock status changed` }); } @@ -994,16 +1002,24 @@ export function useMergeStockItem(props: StockOperationProps) { ...props, fieldGenerator: stockMergeFields, endpoint: ApiEndpoints.stock_merge, - title: t`Merge Stock` + title: t`Merge Stock`, + successMessage: t`Stock merged` }); } export function useAssignStockItem(props: StockOperationProps) { + // Filter items - only allow 'salable' items + const items = useMemo(() => { + return props.items?.filter((item) => item?.part_detail?.salable); + }, [props.items]); + return stockOperationModal({ ...props, + items: items, fieldGenerator: stockAssignFields, endpoint: ApiEndpoints.stock_assign, - title: t`Assign Stock to Customer` + title: t`Assign Stock to Customer`, + successMessage: t`Stock assigned to customer` }); } @@ -1013,7 +1029,8 @@ export function useDeleteStockItem(props: StockOperationProps) { fieldGenerator: stockDeleteFields, endpoint: ApiEndpoints.stock_item_list, modalFunc: useDeleteApiFormModal, - title: t`Delete Stock Items` + title: t`Delete Stock Items`, + successMessage: t`Stock deleted` }); } diff --git a/src/frontend/src/pages/stock/StockDetail.tsx b/src/frontend/src/pages/stock/StockDetail.tsx index 564aec8416..1c0c7e684d 100644 --- a/src/frontend/src/pages/stock/StockDetail.tsx +++ b/src/frontend/src/pages/stock/StockDetail.tsx @@ -48,6 +48,7 @@ import { UserRoles } from '../../enums/Roles'; import { type StockOperationProps, useAddStockItem, + useAssignStockItem, useCountStockItem, useRemoveStockItem, useStockFields, @@ -588,7 +589,7 @@ export default function StockDetail() { const stockActionProps: StockOperationProps = useMemo(() => { return { - items: stockitem, + items: [stockitem], model: ModelType.stockitem, refresh: refreshInstance, filters: { @@ -601,6 +602,7 @@ export default function StockDetail() { const addStockItem = useAddStockItem(stockActionProps); const removeStockItem = useRemoveStockItem(stockActionProps); const transferStockItem = useTransferStockItem(stockActionProps); + const assignToCustomer = useAssignStockItem(stockActionProps); const serializeStockFields = useStockItemSerializeFields({ partId: stockitem.part, @@ -731,7 +733,7 @@ export default function StockDetail() { { name: t`Return`, tooltip: t`Return from customer`, - hidden: !stockitem.sales_order, + hidden: !stockitem.customer, icon: ( { stockitem.pk && returnStockItem.open(); } + }, + { + name: t`Assign to Customer`, + tooltip: t`Assign to a customer`, + hidden: !!stockitem.customer, + icon: ( + + ), + onClick: () => { + stockitem.pk && assignToCustomer.open(); + } } ]} />, @@ -874,6 +887,7 @@ export default function StockDetail() { {transferStockItem.modal} {serializeStockItem.modal} {returnStockItem.modal} + {assignToCustomer.modal} ); diff --git a/src/frontend/src/tables/stock/StockItemTable.tsx b/src/frontend/src/tables/stock/StockItemTable.tsx index 62c0ff115e..de53c5d9fd 100644 --- a/src/frontend/src/tables/stock/StockItemTable.tsx +++ b/src/frontend/src/tables/stock/StockItemTable.tsx @@ -604,7 +604,7 @@ export function StockItemTable({ { name: t`Assign to customer`, icon: , - tooltip: t`Order new stock`, + tooltip: t`Assign items to a customer`, disabled: !can_add_stock, onClick: () => { assignStock.open(); diff --git a/src/frontend/tests/pages/pui_stock.spec.ts b/src/frontend/tests/pages/pui_stock.spec.ts index 3737250b87..5d23703732 100644 --- a/src/frontend/tests/pages/pui_stock.spec.ts +++ b/src/frontend/tests/pages/pui_stock.spec.ts @@ -189,7 +189,7 @@ test('Stock - Stock Actions', async ({ page }) => { await page.getByRole('button', { name: 'Cancel' }).click(); // Find an item which has been sent to a customer - await page.goto(`${baseUrl}/stock/item/1012/details`); + await page.goto(`${baseUrl}/stock/item/1014/details`); await page.getByText('Batch Code: 2022-11-12').waitFor(); await page.getByText('Unavailable').waitFor(); await page.getByLabel('action-menu-stock-operations').click(); From a48d23b161266e2853a7f6cd827cafe10966c7b1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 28 Nov 2024 00:09:18 +1100 Subject: [PATCH 19/19] Set status when returning from customer (#8571) * Set status when returning from customer * Fix default customer for return order table * Set status when receiving items against a ReturnOrder * Bump max query time for currency endpoint * Bump API version --- .../InvenTree/InvenTree/api_version.py | 5 ++- src/backend/InvenTree/common/tests.py | 4 ++- src/backend/InvenTree/order/models.py | 36 ++++++++++++------- src/backend/InvenTree/order/serializers.py | 31 ++++++++++++++-- src/backend/InvenTree/stock/models.py | 28 ++++++++++----- src/backend/InvenTree/stock/serializers.py | 19 ++++++++-- src/frontend/src/forms/ReturnOrderForms.tsx | 32 +++++++++++++++-- src/frontend/src/pages/stock/StockDetail.tsx | 4 ++- .../src/tables/sales/ReturnOrderTable.tsx | 3 ++ 9 files changed, 130 insertions(+), 32 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 2d1b4e364b..c90fe14e59 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,13 +1,16 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 286 +INVENTREE_API_VERSION = 287 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v287 - 2024-11-27 : https://github.com/inventree/InvenTree/pull/8571 + - Adds ability to set stock status when returning items from a customer + v286 - 2024-11-26 : https://github.com/inventree/InvenTree/pull/8054 - Adds "SelectionList" and "SelectionListEntry" API endpoints diff --git a/src/backend/InvenTree/common/tests.py b/src/backend/InvenTree/common/tests.py index e07afacb93..2b1a092633 100644 --- a/src/backend/InvenTree/common/tests.py +++ b/src/backend/InvenTree/common/tests.py @@ -1254,7 +1254,9 @@ class CurrencyAPITests(InvenTreeAPITestCase): # Updating via the external exchange may not work every time for _idx in range(5): - self.post(reverse('api-currency-refresh'), expected_code=200) + self.post( + reverse('api-currency-refresh'), expected_code=200, max_query_time=30 + ) # There should be some new exchange rate objects now if Rate.objects.all().exists(): diff --git a/src/backend/InvenTree/order/models.py b/src/backend/InvenTree/order/models.py index 8578974711..9eeeec0aff 100644 --- a/src/backend/InvenTree/order/models.py +++ b/src/backend/InvenTree/order/models.py @@ -2363,14 +2363,23 @@ class ReturnOrder(TotalPriceMixin, Order): # endregion @transaction.atomic - def receive_line_item(self, line, location, user, note='', **kwargs): + def receive_line_item(self, line, location, user, **kwargs): """Receive a line item against this ReturnOrder. - Rules: - - Transfers the StockItem to the specified location - - Marks the StockItem as "quarantined" - - Adds a tracking entry to the StockItem - - Removes the 'customer' reference from the StockItem + Arguments: + line: ReturnOrderLineItem to receive + location: StockLocation to receive the item to + user: User performing the action + + Keyword Arguments: + note: Additional notes to add to the tracking entry + status: Status to set the StockItem to (default: StockStatus.QUARANTINED) + + Performs the following actions: + - Transfers the StockItem to the specified location + - Marks the StockItem as "quarantined" + - Adds a tracking entry to the StockItem + - Removes the 'customer' reference from the StockItem """ # Prevent an item from being "received" multiple times if line.received_date is not None: @@ -2379,17 +2388,18 @@ class ReturnOrder(TotalPriceMixin, Order): stock_item = line.item - deltas = { - 'status': StockStatus.QUARANTINED.value, - 'returnorder': self.pk, - 'location': location.pk, - } + status = kwargs.get('status') + + if status is None: + status = StockStatus.QUARANTINED.value + + deltas = {'status': status, 'returnorder': self.pk, 'location': location.pk} if stock_item.customer: deltas['customer'] = stock_item.customer.pk # Update the StockItem - stock_item.status = kwargs.get('status', StockStatus.QUARANTINED.value) + stock_item.status = status stock_item.location = location stock_item.customer = None stock_item.sales_order = None @@ -2400,7 +2410,7 @@ class ReturnOrder(TotalPriceMixin, Order): stock_item.add_tracking_entry( StockHistoryCode.RETURNED_AGAINST_RETURN_ORDER, user, - notes=note, + notes=kwargs.get('note', ''), deltas=deltas, location=location, returnorder=self, diff --git a/src/backend/InvenTree/order/serializers.py b/src/backend/InvenTree/order/serializers.py index 936b8e0f3e..02955e957b 100644 --- a/src/backend/InvenTree/order/serializers.py +++ b/src/backend/InvenTree/order/serializers.py @@ -26,6 +26,7 @@ import part.filters as part_filters import part.models as part_models import stock.models import stock.serializers +import stock.status_codes from common.serializers import ProjectCodeSerializer from company.serializers import ( AddressBriefSerializer, @@ -1923,7 +1924,7 @@ class ReturnOrderLineItemReceiveSerializer(serializers.Serializer): class Meta: """Metaclass options.""" - fields = ['item'] + fields = ['item', 'status'] item = serializers.PrimaryKeyRelatedField( queryset=order.models.ReturnOrderLineItem.objects.all(), @@ -1933,6 +1934,15 @@ class ReturnOrderLineItemReceiveSerializer(serializers.Serializer): label=_('Return order line item'), ) + status = serializers.ChoiceField( + choices=stock.status_codes.StockStatus.items(), + default=None, + label=_('Status'), + help_text=_('Stock item status code'), + required=False, + allow_blank=True, + ) + def validate_line_item(self, item): """Validation for a single line item.""" if item.order != self.context['order']: @@ -1950,7 +1960,7 @@ class ReturnOrderReceiveSerializer(serializers.Serializer): class Meta: """Metaclass options.""" - fields = ['items', 'location'] + fields = ['items', 'location', 'note'] items = ReturnOrderLineItemReceiveSerializer(many=True) @@ -1963,6 +1973,14 @@ class ReturnOrderReceiveSerializer(serializers.Serializer): help_text=_('Select destination location for received items'), ) + note = serializers.CharField( + label=_('Note'), + help_text=_('Additional note for incoming stock items'), + required=False, + default='', + allow_blank=True, + ) + def validate(self, data): """Perform data validation for this serializer.""" order = self.context['order'] @@ -1993,7 +2011,14 @@ class ReturnOrderReceiveSerializer(serializers.Serializer): with transaction.atomic(): for item in items: line_item = item['item'] - order.receive_line_item(line_item, location, request.user) + + order.receive_line_item( + line_item, + location, + request.user, + note=data.get('note', ''), + status=item.get('status', None), + ) @register_importer() diff --git a/src/backend/InvenTree/stock/models.py b/src/backend/InvenTree/stock/models.py index b414b8592e..29aa84cc50 100644 --- a/src/backend/InvenTree/stock/models.py +++ b/src/backend/InvenTree/stock/models.py @@ -1217,8 +1217,16 @@ class StockItem( def return_from_customer(self, location, user=None, **kwargs): """Return stock item from customer, back into the specified location. + Arguments: + location: The location to return the stock item to + user: The user performing the action + + Keyword Arguments: + notes: Additional notes to add to the tracking entry + status: Optionally set the status of the stock item + If the selected location is the same as the parent, merge stock back into the parent. - Otherwise create the stock in the new location + Otherwise create the stock in the new location. """ notes = kwargs.get('notes', '') @@ -1228,6 +1236,17 @@ class StockItem( tracking_info['customer'] = self.customer.id tracking_info['customer_name'] = self.customer.name + # Clear out allocation information for the stock item + self.customer = None + self.belongs_to = None + self.sales_order = None + self.location = location + self.clearAllocations() + + if status := kwargs.get('status'): + self.status = status + tracking_info['status'] = status + self.add_tracking_entry( StockHistoryCode.RETURNED_FROM_CUSTOMER, user, @@ -1236,13 +1255,6 @@ class StockItem( location=location, ) - # Clear out allocation information for the stock item - self.customer = None - self.belongs_to = None - self.sales_order = None - self.location = location - self.clearAllocations() - trigger_event('stockitem.returnedfromcustomer', id=self.id) """If new location is the same as the parent location, merge this stock back in the parent""" diff --git a/src/backend/InvenTree/stock/serializers.py b/src/backend/InvenTree/stock/serializers.py index da958c67ef..ccc14c8804 100644 --- a/src/backend/InvenTree/stock/serializers.py +++ b/src/backend/InvenTree/stock/serializers.py @@ -968,7 +968,7 @@ class ReturnStockItemSerializer(serializers.Serializer): class Meta: """Metaclass options.""" - fields = ['location', 'note'] + fields = ['location', 'status', 'notes'] location = serializers.PrimaryKeyRelatedField( queryset=StockLocation.objects.all(), @@ -979,6 +979,15 @@ class ReturnStockItemSerializer(serializers.Serializer): help_text=_('Destination location for returned item'), ) + status = serializers.ChoiceField( + choices=stock.status_codes.StockStatus.items(), + default=None, + label=_('Status'), + help_text=_('Stock item status code'), + required=False, + allow_blank=True, + ) + notes = serializers.CharField( label=_('Notes'), help_text=_('Add transaction note (optional)'), @@ -994,9 +1003,13 @@ class ReturnStockItemSerializer(serializers.Serializer): data = self.validated_data location = data['location'] - notes = data.get('notes', '') - item.return_from_customer(location, user=request.user, notes=notes) + item.return_from_customer( + location, + user=request.user, + notes=data.get('notes', ''), + status=data.get('status', None), + ) class StockChangeStatusSerializer(serializers.Serializer): diff --git a/src/frontend/src/forms/ReturnOrderForms.tsx b/src/frontend/src/forms/ReturnOrderForms.tsx index 805c94b3ec..4fe37b66fd 100644 --- a/src/frontend/src/forms/ReturnOrderForms.tsx +++ b/src/frontend/src/forms/ReturnOrderForms.tsx @@ -4,6 +4,7 @@ import { IconAddressBook, IconUser, IconUsers } from '@tabler/icons-react'; import { useMemo } from 'react'; import RemoveRowButton from '../components/buttons/RemoveRowButton'; +import { StandaloneField } from '../components/forms/StandaloneField'; import type { ApiFormAdjustFilterType, ApiFormFieldSet @@ -11,8 +12,10 @@ import type { import type { TableFieldRowProps } from '../components/forms/fields/TableField'; import { Thumbnail } from '../components/images/Thumbnail'; import { ApiEndpoints } from '../enums/ApiEndpoints'; +import { ModelType } from '../enums/ModelType'; import { useCreateApiFormModal } from '../hooks/UseForm'; import { apiUrl } from '../states/ApiState'; +import { StatusFilterOptions } from '../tables/Filter'; export function useReturnOrderFields({ duplicateOrderId @@ -133,6 +136,17 @@ function ReturnOrderLineItemFormRow({ props: TableFieldRowProps; record: any; }>) { + const statusOptions = useMemo(() => { + return ( + StatusFilterOptions(ModelType.stockitem)()?.map((choice) => { + return { + value: choice.value, + display_name: choice.label + }; + }) ?? [] + ); + }, []); + return ( <> @@ -146,7 +160,21 @@ function ReturnOrderLineItemFormRow({
{record.part_detail.name}
- {record.item_detail.serial} + # {record.item_detail.serial} + + { + props.changeFn(props.idx, 'status', value); + } + }} + defaultValue={record.item_detail?.status} + error={props.rowErrors?.status?.message} + /> + props.removeFn(props.idx)} /> @@ -181,7 +209,7 @@ export function useReceiveReturnOrderLineItems( /> ); }, - headers: [t`Part`, t`Serial Number`] + headers: [t`Part`, t`Stock Item`, t`Status`] }, location: { filters: { diff --git a/src/frontend/src/pages/stock/StockDetail.tsx b/src/frontend/src/pages/stock/StockDetail.tsx index 1c0c7e684d..db3eecab2c 100644 --- a/src/frontend/src/pages/stock/StockDetail.tsx +++ b/src/frontend/src/pages/stock/StockDetail.tsx @@ -639,10 +639,12 @@ export default function StockDetail() { ), fields: { location: {}, + status: {}, notes: {} }, initialData: { - location: stockitem.location ?? stockitem.part_detail?.default_location + location: stockitem.location ?? stockitem.part_detail?.default_location, + status: stockitem.status_custom_key ?? stockitem.status }, successMessage: t`Item returned to stock`, onFormSuccess: () => { diff --git a/src/frontend/src/tables/sales/ReturnOrderTable.tsx b/src/frontend/src/tables/sales/ReturnOrderTable.tsx index d086b7ad6f..6a5f6f9694 100644 --- a/src/frontend/src/tables/sales/ReturnOrderTable.tsx +++ b/src/frontend/src/tables/sales/ReturnOrderTable.tsx @@ -152,6 +152,9 @@ export function ReturnOrderTable({ url: ApiEndpoints.return_order_list, title: t`Add Return Order`, fields: returnOrderFields, + initialData: { + customer: customerId + }, follow: true, modelType: ModelType.returnorder });