mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Url field fix (#3488)
* Updates for automated metadata extraction * Update link field for StockItem model - Increase max_length to 200 characters - Custom migration - Updates for InvenTreeUrlField model * Adding unit tests * Bug fix for metadata.py
This commit is contained in:
parent
83b471b4f7
commit
63d221854b
@ -6,7 +6,6 @@ from decimal import Decimal
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.db import models as models
|
from django.db import models as models
|
||||||
from django.forms.fields import URLField as FormURLField
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from djmoney.forms.fields import MoneyField
|
from djmoney.forms.fields import MoneyField
|
||||||
@ -23,26 +22,28 @@ class InvenTreeRestURLField(RestURLField):
|
|||||||
"""Custom field for DRF with custom scheme vaildators."""
|
"""Custom field for DRF with custom scheme vaildators."""
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Update schemes."""
|
"""Update schemes."""
|
||||||
|
|
||||||
|
# Enforce 'max length' parameter in form validation
|
||||||
|
if 'max_length' not in kwargs:
|
||||||
|
kwargs['max_length'] = 200
|
||||||
|
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.validators[-1].schemes = allowable_url_schemes()
|
self.validators[-1].schemes = allowable_url_schemes()
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeURLFormField(FormURLField):
|
|
||||||
"""Custom URL form field with custom scheme validators."""
|
|
||||||
|
|
||||||
default_validators = [validators.URLValidator(schemes=allowable_url_schemes())]
|
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeURLField(models.URLField):
|
class InvenTreeURLField(models.URLField):
|
||||||
"""Custom URL field which has custom scheme validators."""
|
"""Custom URL field which has custom scheme validators."""
|
||||||
|
|
||||||
validators = [validators.URLValidator(schemes=allowable_url_schemes())]
|
default_validators = [validators.URLValidator(schemes=allowable_url_schemes())]
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Return a Field instance for this field."""
|
"""Initialization method for InvenTreeURLField"""
|
||||||
return super().formfield(**{
|
|
||||||
'form_class': InvenTreeURLFormField
|
# Max length for InvenTreeURLField defaults to 200
|
||||||
})
|
if 'max_length' not in kwargs:
|
||||||
|
kwargs['max_length'] = 200
|
||||||
|
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
def money_kwargs():
|
def money_kwargs():
|
||||||
|
@ -116,6 +116,12 @@ class InvenTreeMetadata(SimpleMetadata):
|
|||||||
|
|
||||||
model_class = None
|
model_class = None
|
||||||
|
|
||||||
|
# Attributes to copy extra attributes from the model to the field (if they don't exist)
|
||||||
|
extra_attributes = [
|
||||||
|
'help_text',
|
||||||
|
'max_length',
|
||||||
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
model_class = serializer.Meta.model
|
model_class = serializer.Meta.model
|
||||||
|
|
||||||
@ -148,10 +154,7 @@ class InvenTreeMetadata(SimpleMetadata):
|
|||||||
elif name in model_default_values:
|
elif name in model_default_values:
|
||||||
serializer_info[name]['default'] = model_default_values[name]
|
serializer_info[name]['default'] = model_default_values[name]
|
||||||
|
|
||||||
# Attributes to copy from the model to the field (if they don't exist)
|
for attr in extra_attributes:
|
||||||
attributes = ['help_text']
|
|
||||||
|
|
||||||
for attr in attributes:
|
|
||||||
if attr not in serializer_info[name]:
|
if attr not in serializer_info[name]:
|
||||||
|
|
||||||
if hasattr(field, attr):
|
if hasattr(field, attr):
|
||||||
@ -172,8 +175,9 @@ class InvenTreeMetadata(SimpleMetadata):
|
|||||||
# This is used to automatically filter AJAX requests
|
# This is used to automatically filter AJAX requests
|
||||||
serializer_info[name]['filters'] = relation.model_field.get_limit_choices_to()
|
serializer_info[name]['filters'] = relation.model_field.get_limit_choices_to()
|
||||||
|
|
||||||
if 'help_text' not in serializer_info[name] and hasattr(relation.model_field, 'help_text'):
|
for attr in extra_attributes:
|
||||||
serializer_info[name]['help_text'] = relation.model_field.help_text
|
if attr not in serializer_info[name] and hasattr(relation.model_field, attr):
|
||||||
|
serializer_info[name][attr] = getattr(relation.model_field, attr)
|
||||||
|
|
||||||
if name in model_default_values:
|
if name in model_default_values:
|
||||||
serializer_info[name]['default'] = model_default_values[name]
|
serializer_info[name]['default'] = model_default_values[name]
|
||||||
|
19
InvenTree/stock/migrations/0082_alter_stockitem_link.py
Normal file
19
InvenTree/stock/migrations/0082_alter_stockitem_link.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 3.2.15 on 2022-08-07 02:38
|
||||||
|
|
||||||
|
import InvenTree.fields
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('stock', '0081_auto_20220801_0044'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stockitem',
|
||||||
|
name='link',
|
||||||
|
field=InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to external URL', max_length=200, verbose_name='External Link'),
|
||||||
|
),
|
||||||
|
]
|
@ -647,7 +647,7 @@ class StockItem(MetadataMixin, MPTTModel):
|
|||||||
|
|
||||||
link = InvenTreeURLField(
|
link = InvenTreeURLField(
|
||||||
verbose_name=_('External Link'),
|
verbose_name=_('External Link'),
|
||||||
max_length=125, blank=True,
|
blank=True, max_length=200,
|
||||||
help_text=_("Link to external URL")
|
help_text=_("Link to external URL")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,6 +44,45 @@ class StockTest(InvenTreeTestCase):
|
|||||||
Part.objects.rebuild()
|
Part.objects.rebuild()
|
||||||
StockItem.objects.rebuild()
|
StockItem.objects.rebuild()
|
||||||
|
|
||||||
|
def test_link(self):
|
||||||
|
"""Test the link URL field validation"""
|
||||||
|
|
||||||
|
item = StockItem.objects.get(pk=1)
|
||||||
|
|
||||||
|
# Check that invalid URLs fail
|
||||||
|
for bad_url in [
|
||||||
|
'test.com',
|
||||||
|
'httpx://abc.xyz',
|
||||||
|
'https:google.com',
|
||||||
|
]:
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
item.link = bad_url
|
||||||
|
item.save()
|
||||||
|
item.full_clean()
|
||||||
|
|
||||||
|
# Check that valid URLs pass
|
||||||
|
for good_url in [
|
||||||
|
'https://test.com',
|
||||||
|
'https://digikey.com/datasheets?file=1010101010101.bin',
|
||||||
|
'ftp://download.com:8080/file.aspx',
|
||||||
|
]:
|
||||||
|
item.link = good_url
|
||||||
|
item.save()
|
||||||
|
item.full_clean()
|
||||||
|
|
||||||
|
# A long URL should fail
|
||||||
|
long_url = 'https://website.co.uk?query=' + 'a' * 173
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
item.link = long_url
|
||||||
|
item.full_clean()
|
||||||
|
|
||||||
|
# Shorten by a single character, will pass
|
||||||
|
long_url = long_url[:-1]
|
||||||
|
|
||||||
|
item.link = long_url
|
||||||
|
item.save()
|
||||||
|
|
||||||
def test_expiry(self):
|
def test_expiry(self):
|
||||||
"""Test expiry date functionality for StockItem model."""
|
"""Test expiry date functionality for StockItem model."""
|
||||||
today = datetime.datetime.now().date()
|
today = datetime.datetime.now().date()
|
||||||
|
Loading…
Reference in New Issue
Block a user