This commit is contained in:
j3d1 2026-08-01 12:17:37 +02:00
parent 32addb8ed1
commit 2f8683add1
15 changed files with 610 additions and 134 deletions

View file

@ -6,6 +6,46 @@ from files.serializers import FileSerializer
from toolshed.models import Category, Property, ItemProperty, InventoryItem, Tag, StorageLocation, WorkflowInstance
def parse_handle(handle):
"""Parse a fully qualified handle like 'git:base#property:length' into (origin, entity_type, name)"""
if '#' not in handle:
# Fallback to old format (just name)
return None, None, handle
origin, rest = handle.split('#', 1)
if ':' not in rest:
return origin, None, rest
entity_type, name = rest.split(':', 1)
return origin, entity_type, name
def resolve_category_handle(handle):
"""Resolve a fully qualified handle to a Category object"""
origin, entity_type, name = parse_handle(handle)
if origin and entity_type == 'category':
return Category.objects.get(origin=origin, name=name)
# Fallback to name-only lookup
return Category.objects.get(name=handle.split('/')[-1])
def resolve_property_handle(handle):
"""Resolve a fully qualified handle to a Property object"""
origin, entity_type, name = parse_handle(handle)
if origin and entity_type == 'property':
return Property.objects.get(origin=origin, name=name)
# Fallback to name-only lookup
return Property.objects.get(name=handle)
def resolve_tag_handle(handle):
"""Resolve a fully qualified handle to a Tag object"""
origin, entity_type, name = parse_handle(handle)
if origin and entity_type == 'tag':
return Tag.objects.get(origin=origin, name=name)
# Fallback to name-only lookup
return Tag.objects.get(name=handle)
class FriendSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField()
@ -29,23 +69,35 @@ class FriendRequestSerializer(serializers.ModelSerializer):
class PropertySerializer(serializers.ModelSerializer):
category = serializers.SlugRelatedField(queryset=Category.objects.all(), slug_field='name')
category = serializers.SerializerMethodField()
handle = serializers.SerializerMethodField()
def get_category(self, obj):
return resolve_category_handle(obj.category.get_handle()) if obj.category else None
def get_handle(self, obj):
return obj.get_handle()
class Meta:
model = Property
fields = ['name', 'description', 'category', 'unit_symbol', 'unit_name', 'unit_name_plural', 'base2_prefix']
fields = ['name', 'description', 'category', 'unit_symbol', 'unit_name', 'unit_name_plural', 'base2_prefix', 'handle']
class CategorySerializer(serializers.ModelSerializer):
handle = serializers.SerializerMethodField()
class Meta:
model = Category
fields = ['name']
fields = ['name', 'handle']
def get_handle(self, obj):
return obj.get_handle()
def to_representation(self, instance):
return str(instance)
return instance.get_handle()
def to_internal_value(self, data):
return Category.objects.get(name=data.split("/")[-1])
return resolve_category_handle(data.split("/")[-1])
class StorageLocationSerializer(serializers.ModelSerializer):
@ -67,23 +119,28 @@ class StorageLocationSerializer(serializers.ModelSerializer):
class ItemPropertySerializer(serializers.ModelSerializer):
property = PropertySerializer(read_only=True)
handle = serializers.SerializerMethodField()
class Meta:
model = ItemProperty
fields = ['property', 'value']
fields = ['property', 'value', 'handle']
def get_handle(self, obj):
return obj.property.get_handle()
def to_representation(self, instance):
return {'value': instance.value, 'name': instance.property.name}
return {'value': instance.value, 'name': instance.property.name, 'handle': instance.property.get_handle()}
def to_internal_value(self, data):
prop = Property.objects.get(name=data['name'])
prop = resolve_property_handle(data.get('name') or data.get('handle'))
value = data['value']
return {'property': prop, 'value': value}
class InventoryItemSerializer(serializers.ModelSerializer):
owner = OwnerSerializer(read_only=True)
tags = serializers.SlugRelatedField(many=True, required=False, queryset=Tag.objects.all(), slug_field='name')
tags = serializers.SerializerMethodField()
tags_input = serializers.ListField(child=serializers.CharField(), write_only=True, required=False)
properties = ItemPropertySerializer(many=True, required=False, source='itemproperty_set')
category = CategorySerializer(required=False, allow_null=True)
files = FileSerializer(many=True, read_only=True)
@ -91,11 +148,16 @@ class InventoryItemSerializer(serializers.ModelSerializer):
class Meta:
model = InventoryItem
fields = ['id', 'name', 'description', 'owner', 'category', 'availability_policy', 'owned_quantity', 'owner',
'tags', 'properties', 'files', 'storage_location']
'tags', 'tags_input', 'properties', 'files', 'storage_location']
def get_tags(self, obj):
return [tag.get_handle() for tag in obj.tags.all()]
def to_internal_value(self, data):
files = data.pop('files', [])
tags_input = data.pop('tags_input', data.pop('tags', []))
ret = super().to_internal_value(data)
ret['tags'] = [resolve_tag_handle(tag) for tag in tags_input]
ret['files'] = files
return ret