Merge branch 'develop'

This commit is contained in:
vabene1111
2025-09-19 17:02:10 +02:00
5 changed files with 48 additions and 7 deletions

View File

@@ -91,8 +91,8 @@ admin.site.register(SearchPreference, SearchPreferenceAdmin)
class AiProviderAdmin(admin.ModelAdmin):
list_display = ('name', 'space', 'model',)
search_fields = ('name', 'space', 'model',)
list_display = ('name', 'space', 'model_name',)
search_fields = ('name', 'space', 'model_name',)
admin.site.register(AiProvider, AiProviderAdmin)

View File

@@ -62,7 +62,7 @@ class AiCallbackHandler(CustomLogger):
remaining_balance = self.space.ai_credits_balance - Decimal(str(credit_cost))
if remaining_balance < 0:
remaining_balance = 0
if settings.HOSTED:
if settings.HOSTED and self.space.ai_credits_monthly == 0:
self.space.ai_enabled = False
self.space.ai_credits_balance = remaining_balance

View File

@@ -417,6 +417,9 @@ class AiProvider(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class AiLog(models.Model, PermissionModelMixin):
F_FILE_IMPORT = 'FILE_IMPORT'
@@ -437,6 +440,9 @@ class AiLog(models.Model, PermissionModelMixin):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.function} {self.ai_provider.name} {self.created_at}"
class ConnectorConfig(models.Model, PermissionModelMixin):
HOMEASSISTANT = 'HomeAssistant'

View File

@@ -335,17 +335,23 @@ class AiProviderSerializer(serializers.ModelSerializer):
return super().create(validated_data)
def update(self, instance, validated_data):
validated_data = self.handle_global_space_logic(validated_data)
validated_data = self.handle_global_space_logic(validated_data, instance=instance)
return super().update(instance, validated_data)
def handle_global_space_logic(self, validated_data):
def handle_global_space_logic(self, validated_data, instance=None):
"""
allow superusers to create AI providers without a space but make sure everyone else only uses their own space
"""
if ('space' not in validated_data or not validated_data['space']) and self.context['request'].user.is_superuser:
validated_data['space'] = None
else:
validated_data['space'] = self.context['request'].space
if instance:
validated_data['space'] = instance.space
else:
validated_data['space'] = self.context['request'].space
if 'log_credit_cost' in validated_data and not self.context['request'].user.is_superuser:
del validated_data['log_credit_cost']
return validated_data
@@ -1709,6 +1715,11 @@ class FdcQuerySerializer(serializers.Serializer):
foods = FdcQueryFoodsSerializer(many=True)
class GenericModelSerializer(serializers.Serializer):
id = serializers.IntegerField()
model = serializers.CharField()
name = serializers.CharField()
# Export/Import Serializers
class KeywordExportSerializer(KeywordSerializer):

View File

@@ -19,12 +19,15 @@ import redis
import requests
from PIL import UnidentifiedImageError
from django.contrib import messages
from django.contrib.admin.utils import get_deleted_objects, NestedObjects
from django.contrib.auth.models import Group, User
from django.contrib.postgres.search import TrigramSimilarity
from django.core.cache import caches
from django.core.exceptions import FieldError, ValidationError
from django.core.files import File
from django.db import DEFAULT_DB_ALIAS
from django.db.models import Case, Count, Exists, OuterRef, ProtectedError, Q, Subquery, Value, When
from django.db.models.deletion import Collector
from django.db.models.fields.related import ForeignObjectRel
from django.db.models.functions import Coalesce, Lower
from django.db.models.signals import post_save
@@ -110,7 +113,7 @@ from cookbook.serializer import (AccessTokenSerializer, AutomationSerializer, Au
LocalizationSerializer, ServerSettingsSerializer, RecipeFromSourceResponseSerializer, ShoppingListEntryBulkCreateSerializer, FdcQuerySerializer,
AiImportSerializer, ImportOpenDataSerializer, ImportOpenDataMetaDataSerializer, ImportOpenDataResponseSerializer, ExportRequestSerializer,
RecipeImportSerializer, ConnectorConfigSerializer, SearchPreferenceSerializer, SearchFieldsSerializer, RecipeBatchUpdateSerializer,
AiProviderSerializer, AiLogSerializer, FoodBatchUpdateSerializer
AiProviderSerializer, AiLogSerializer, FoodBatchUpdateSerializer, GenericModelSerializer
)
from cookbook.version_info import TANDOOR_VERSION
from cookbook.views.import_export import get_integration
@@ -1648,6 +1651,27 @@ class PropertyTypeViewSet(LoggingMixin, viewsets.ModelViewSet):
self.queryset.filter(category__in=category)
return self.queryset.filter(space=self.request.space)
@extend_schema(responses=GenericModelSerializer(many=True))
@decorators.action(detail=True, methods=['GET'], serializer_class=GenericModelSerializer, pagination_class=DefaultPagination)
# TODO actually implement pagination
def protecting(self, request, pk):
obj = self.queryset.filter(pk=pk, space=request.space).first()
if obj:
collector = NestedObjects(using=DEFAULT_DB_ALIAS)
collector.collect([obj])
protected_objects = []
for o in collector.protected:
protected_objects.append({
'id': o.pk,
'model': o.__class__.__name__,
'name': str(o),
})
return Response(self.serializer_class(protected_objects, many=True, context={'request': request}).data)
else:
return Response({}, status=status.HTTP_404_NOT_FOUND)
class PropertyViewSet(LoggingMixin, viewsets.ModelViewSet):
queryset = Property.objects