From f4a7ef144fb9b65d67c1ad5ed3a322a14bd6866c Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Sun, 22 Jun 2025 13:37:02 +0200 Subject: [PATCH] moved search settings to frontend --- cookbook/forms.py | 35 - cookbook/serializer.py | 36 +- cookbook/urls.py | 2 + cookbook/views/api.py | 31 +- vue3/src/apps/tandoor/main.ts | 1 + vue3/src/components/inputs/ModelSelect.vue | 2 + .../components/settings/SearchSettings.vue | 176 +++ vue3/src/locales/ar.json | 885 +++++++------ vue3/src/locales/bg.json | 857 ++++++------ vue3/src/locales/ca.json | 1159 ++++++++-------- vue3/src/locales/cs.json | 1139 ++++++++-------- vue3/src/locales/da.json | 1159 ++++++++-------- vue3/src/locales/de.json | 17 + vue3/src/locales/el.json | 1159 ++++++++-------- vue3/src/locales/en.json | 17 + vue3/src/locales/es.json | 1153 ++++++++-------- vue3/src/locales/fi.json | 1061 +++++++-------- vue3/src/locales/fr.json | 1127 ++++++++-------- vue3/src/locales/he.json | 1157 ++++++++-------- vue3/src/locales/hr.json | 1159 ++++++++-------- vue3/src/locales/hu.json | 1065 +++++++-------- vue3/src/locales/hy.json | 281 ++-- vue3/src/locales/id.json | 937 ++++++------- vue3/src/locales/is.json | 1153 ++++++++-------- vue3/src/locales/it.json | 1163 ++++++++-------- vue3/src/locales/lt.json | 1087 +++++++-------- vue3/src/locales/lv.json | 1159 ++++++++-------- vue3/src/locales/nb_NO.json | 1061 +++++++-------- vue3/src/locales/nl.json | 1167 +++++++++-------- vue3/src/locales/pl.json | 1163 ++++++++-------- vue3/src/locales/pt.json | 925 ++++++------- vue3/src/locales/pt_BR.json | 1161 ++++++++-------- vue3/src/locales/ro.json | 979 +++++++------- vue3/src/locales/ru.json | 991 +++++++------- vue3/src/locales/sl.json | 1163 ++++++++-------- vue3/src/locales/sv.json | 1161 ++++++++-------- vue3/src/locales/tr.json | 1159 ++++++++-------- vue3/src/locales/uk.json | 985 +++++++------- vue3/src/locales/zh_Hans.json | 1161 ++++++++-------- vue3/src/locales/zh_Hant.json | 1159 ++++++++-------- vue3/src/openapi/.openapi-generator/FILES | 4 + vue3/src/openapi/apis/ApiApi.ts | 216 ++- .../openapi/models/PatchedSearchPreference.ts | 142 ++ vue3/src/openapi/models/SearchEnum.ts | 54 + vue3/src/openapi/models/SearchFields.ts | 110 ++ vue3/src/openapi/models/SearchPreference.ts | 143 ++ vue3/src/openapi/models/index.ts | 4 + vue3/src/pages/SettingsPage.vue | 2 +- vue3/src/types/Models.ts | 21 +- 49 files changed, 17772 insertions(+), 16336 deletions(-) create mode 100644 vue3/src/components/settings/SearchSettings.vue create mode 100644 vue3/src/openapi/models/PatchedSearchPreference.ts create mode 100644 vue3/src/openapi/models/SearchEnum.ts create mode 100644 vue3/src/openapi/models/SearchFields.ts create mode 100644 vue3/src/openapi/models/SearchPreference.ts diff --git a/cookbook/forms.py b/cookbook/forms.py index d38e4b517..4c1f1bf3d 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -173,38 +173,3 @@ class UserCreateForm(forms.Form): name = forms.CharField(label='Username') password = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password', 'type': 'password'})) password_confirm = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password', 'type': 'password'})) - - -class SearchPreferenceForm(forms.ModelForm): - prefix = 'search' - trigram_threshold = forms.DecimalField(min_value=0.01, - max_value=1, - decimal_places=2, - widget=NumberInput(attrs={'class': "form-control-range", 'type': 'range'}), - help_text=_('Determines how fuzzy a search is if it uses trigram similarity matching (e.g. low values mean more typos are ignored).')) - preset = forms.CharField(widget=forms.HiddenInput(), required=False) - - class Meta: - model = SearchPreference - fields = ('search', 'lookup', 'unaccent', 'icontains', 'istartswith', 'trigram', 'fulltext', 'trigram_threshold') - - help_texts = { - 'search': _('Select type method of search. Click here for full description of choices.'), 'lookup': - _('Use fuzzy matching on units, keywords and ingredients when editing and importing recipes.'), 'unaccent': - _('Fields to search ignoring accents. Selecting this option can improve or degrade search quality depending on language'), 'icontains': - _("Fields to search for partial matches. (e.g. searching for 'Pie' will return 'pie' and 'piece' and 'soapie')"), 'istartswith': - _("Fields to search for beginning of word matches. (e.g. searching for 'sa' will return 'salad' and 'sandwich')"), 'trigram': - _("Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) Note: this option will conflict with 'web' and 'raw' methods of search."), - 'fulltext': - _("Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods only function with fulltext fields."), - } - - labels = { - 'search': _('Search Method'), 'lookup': _('Fuzzy Lookups'), 'unaccent': _('Ignore Accent'), 'icontains': _("Partial Match"), 'istartswith': _("Starts With"), - 'trigram': _("Fuzzy Search"), 'fulltext': _("Full Text") - } - - widgets = { - 'search': SelectWidget, 'unaccent': MultiSelectWidget, 'icontains': MultiSelectWidget, 'istartswith': MultiSelectWidget, 'trigram': MultiSelectWidget, 'fulltext': - MultiSelectWidget, - } diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 395fb2812..69052a305 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -36,7 +36,7 @@ from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Cu ShareLink, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage, Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, Unit, UnitConversion, - UserFile, UserPreference, UserSpace, ViewLog, ConnectorConfig) + UserFile, UserPreference, UserSpace, ViewLog, ConnectorConfig, SearchPreference, SearchFields) from cookbook.templatetags.custom_tags import markdown from recipes.settings import AWS_ENABLED, MEDIA_URL, EMAIL_HOST @@ -452,6 +452,40 @@ class UserPreferenceSerializer(WritableNestedModelSerializer): read_only_fields = ('user',) +class SearchFieldsSerializer(UniqueFieldsMixin, WritableNestedModelSerializer): + name = serializers.CharField(allow_null=True, allow_blank=True, required=False) + field = serializers.CharField(allow_null=True, allow_blank=True, required=False) + + def create(self, validated_data): + raise ValidationError('Cannot create using this endpoint') + + def update(self, instance, validated_data): + return instance + + class Meta: + model = SearchFields + fields = ('id', 'name', 'field',) + read_only_fields = ('id',) + + +class SearchPreferenceSerializer(WritableNestedModelSerializer): + user = UserSerializer(read_only=True) + + unaccent = SearchFieldsSerializer(many=True, allow_null=True, required=False) + icontains = SearchFieldsSerializer(many=True, allow_null=True, required=False) + istartswith = SearchFieldsSerializer(many=True, allow_null=True, required=False) + trigram = SearchFieldsSerializer(many=True, allow_null=True, required=False) + fulltext = SearchFieldsSerializer(many=True, allow_null=True, required=False) + + def create(self, validated_data): + raise ValidationError('Cannot create using this endpoint') + + class Meta: + model = SearchPreference + fields = ('user', 'search', 'lookup', 'unaccent', 'icontains', 'istartswith', 'trigram', 'fulltext', 'trigram_threshold') + read_only_fields = ('user',) + + class ConnectorConfigSerializer(SpacedModelSerializer): def create(self, validated_data): diff --git a/cookbook/urls.py b/cookbook/urls.py index 4943fe623..3ed3d3d79 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -56,6 +56,8 @@ router.register(r'unit', api.UnitViewSet) router.register(r'user-file', api.UserFileViewSet) router.register(r'user', api.UserViewSet) router.register(r'user-preference', api.UserPreferenceViewSet) +router.register(r'search-fields', api.SearchFieldsViewSet) +router.register(r'search-preference', api.SearchPreferenceViewSet) router.register(r'user-space', api.UserSpaceViewSet) router.register(r'view-log', api.ViewLogViewSet) router.register(r'access-token', api.AccessTokenViewSet) diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 36484612f..13b12d42d 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -85,7 +85,7 @@ from cookbook.models import (Automation, BookmarkletImport, ConnectorConfig, Coo RecipeBookEntry, ShareLink, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage, Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, Unit, UnitConversion, - UserFile, UserPreference, UserSpace, ViewLog, RecipeImport + UserFile, UserPreference, UserSpace, ViewLog, RecipeImport, SearchPreference, SearchFields ) from cookbook.provider.dropbox import Dropbox from cookbook.provider.local import Local @@ -110,7 +110,7 @@ from cookbook.serializer import (AccessTokenSerializer, AutomationSerializer, Au UserSerializer, UserSpaceSerializer, ViewLogSerializer, LocalizationSerializer, ServerSettingsSerializer, RecipeFromSourceResponseSerializer, ShoppingListEntryBulkCreateSerializer, FdcQuerySerializer, AiImportSerializer, ImportOpenDataSerializer, ImportOpenDataMetaDataSerializer, ImportOpenDataResponseSerializer, ExportRequestSerializer, - RecipeImportSerializer, ConnectorConfigSerializer + RecipeImportSerializer, ConnectorConfigSerializer, SearchPreferenceSerializer, SearchFieldsSerializer ) from cookbook.version_info import TANDOOR_VERSION from cookbook.views.import_export import get_integration @@ -577,7 +577,30 @@ class UserPreferenceViewSet(LoggingMixin, viewsets.ModelViewSet): http_method_names = ['get', 'patch', ] def get_queryset(self): - with scopes_disabled(): # need to disable scopes as user preference is no longer a spaced method + with scopes_disabled(): # need to disable scopes as user preferences are not scoped + return self.queryset.filter(user=self.request.user) + + +class SearchFieldsViewSet(LoggingMixin, viewsets.ReadOnlyModelViewSet): + queryset = SearchFields.objects + serializer_class = SearchFieldsSerializer + permission_classes = [CustomIsGuest & CustomTokenHasReadWriteScope] + pagination_disabled = True + + def get_queryset(self): + with scopes_disabled(): # need to disable scopes as fields are global + return self.queryset + + +class SearchPreferenceViewSet(LoggingMixin, viewsets.ModelViewSet): + queryset = SearchPreference.objects + serializer_class = SearchPreferenceSerializer + permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope] + pagination_disabled = True + http_method_names = ['get', 'patch', ] + + def get_queryset(self): + with scopes_disabled(): # need to disable scopes as search preferences are not scoped return self.queryset.filter(user=self.request.user) @@ -2296,7 +2319,7 @@ def get_external_file_link(request, pk): @api_view(['GET']) @permission_classes([CustomRecipePermission & CustomTokenHasReadWriteScope]) def get_recipe_file(request, pk): - recipe = get_object_or_404(Recipe, pk=pk) # space check handled by CustomRecipePermission + recipe = get_object_or_404(Recipe, pk=pk) # space check handled by CustomRecipePermission if recipe.storage: return FileResponse(get_recipe_provider(recipe).get_file(recipe), filename=f'{recipe.name}.pdf') else: diff --git a/vue3/src/apps/tandoor/main.ts b/vue3/src/apps/tandoor/main.ts index b9b8168f3..110a820e9 100644 --- a/vue3/src/apps/tandoor/main.ts +++ b/vue3/src/apps/tandoor/main.ts @@ -25,6 +25,7 @@ const routes = [ {path: 'cosmetic', component: () => import("@/components/settings/CosmeticSettings.vue"), name: 'CosmeticSettings'}, {path: 'shopping', component: () => import("@/components/settings/ShoppingSettings.vue"), name: 'ShoppingSettings'}, {path: 'meal-plan', component: () => import("@/components/settings/MealPlanSettings.vue"), name: 'MealPlanSettings'}, + {path: 'search', component: () => import("@/components/settings/SearchSettings.vue"), name: 'SearchSettings'}, {path: 'space', component: () => import("@/components/settings/SpaceSettings.vue"), name: 'SpaceSettings'}, {path: 'space-members', component: () => import("@/components/settings/SpaceMemberSettings.vue"), name: 'SpaceMemberSettings'}, {path: 'user-space', component: () => import("@/components/settings/UserSpaceSettings.vue"), name: 'UserSpaceSettings'}, diff --git a/vue3/src/components/inputs/ModelSelect.vue b/vue3/src/components/inputs/ModelSelect.vue index 6eea6eef9..2113d356a 100644 --- a/vue3/src/components/inputs/ModelSelect.vue +++ b/vue3/src/components/inputs/ModelSelect.vue @@ -1,5 +1,7 @@