created CustomFilter model and api

This commit is contained in:
Chris Scoggins
2022-01-21 15:50:26 -06:00
parent 492febe626
commit 890e9e7242
14 changed files with 637 additions and 49 deletions

View File

@@ -0,0 +1,36 @@
# Generated by Django 3.2.11 on 2022-01-21 20:27
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import cookbook.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cookbook', '0167_userpreference_left_handed'),
]
operations = [
migrations.CreateModel(
name='CustomFilter',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128)),
('type', models.CharField(choices=[('RECIPE', 'Recipe'), ('FOOD', 'Food'), ('KEYWORD', 'Keyword')], default=('RECIPE', 'Recipe'), max_length=128)),
('search', models.TextField()),
('created_at', models.DateTimeField(auto_now_add=True)),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('shared', models.ManyToManyField(blank=True, related_name='f_shared_with', to=settings.AUTH_USER_MODEL)),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
migrations.AddConstraint(
model_name='customfilter',
constraint=models.UniqueConstraint(fields=('space', 'name'), name='cf_unique_name_per_space'),
),
]

View File

@@ -1100,3 +1100,34 @@ class Automation(ExportModelOperationsMixin('automations'), models.Model, Permis
objects = ScopedManager(space='space')
space = models.ForeignKey(Space, on_delete=models.CASCADE)
class CustomFilter(models.Model, PermissionModelMixin):
RECIPE = 'RECIPE'
FOOD = 'FOOD'
KEYWORD = 'KEYWORD'
MODELS = (
(RECIPE, _('Recipe')),
(FOOD, _('Food')),
(KEYWORD, _('Keyword')),
)
name = models.CharField(max_length=128, null=False, blank=False)
type = models.CharField(max_length=128, choices=(MODELS), default=MODELS[0])
# could use JSONField, but requires installing extension on SQLite, don't need to search the objects, so seems unecessary
search = models.TextField(blank=False, null=False)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
shared = models.ManyToManyField(User, blank=True, related_name='f_shared_with')
objects = ScopedManager(space='space')
space = models.ForeignKey(Space, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
constraints = [
models.UniqueConstraint(fields=['space', 'name'], name='cf_unique_name_per_space')
]

View File

@@ -14,7 +14,7 @@ from rest_framework.fields import empty
from cookbook.helper.HelperFunctions import str2bool
from cookbook.helper.shopping_helper import RecipeShoppingEditor
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Food,
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, CustomFilter, Food,
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
NutritionInformation, Recipe, RecipeBook, RecipeBookEntry,
RecipeImport, ShareLink, ShoppingList, ShoppingListEntry,
@@ -976,3 +976,16 @@ class FoodShoppingUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Recipe
fields = ['id', 'amount', 'unit', 'delete', ]
class CustomFilterSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
shared = UserNameSerializer(many=True, required=False)
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
return super().create(validated_data)
class Meta:
model = CustomFilter
fields = ('id', 'name', 'search', 'shared', 'created_by')
read_only_fields = ('created_by',)

File diff suppressed because one or more lines are too long

View File

@@ -9,15 +9,17 @@ from cookbook.helper import dal
from recipes.settings import DEBUG
from recipes.version import VERSION_NUMBER
from .models import (Automation, Comment, Food, InviteLink, Keyword, MealPlan, Recipe, RecipeBook,
RecipeBookEntry, RecipeImport, ShoppingList, Step, Storage, Supermarket,
SupermarketCategory, Sync, SyncLog, Unit, UserFile, get_model_name)
from .models import (Automation, Comment, CustomFilter, Food, InviteLink, Keyword, MealPlan, Recipe,
RecipeBook, RecipeBookEntry, RecipeImport, ShoppingList, Step, Storage,
Supermarket, SupermarketCategory, Sync, SyncLog, Unit, UserFile,
get_model_name)
from .views import api, data, delete, edit, import_export, lists, new, telegram, views
router = routers.DefaultRouter()
router.register(r'automation', api.AutomationViewSet)
router.register(r'bookmarklet-import', api.BookmarkletImportViewSet)
router.register(r'cook-log', api.CookLogViewSet)
router.register(r'custom-filter', api.CustomFilterViewSet)
router.register(r'food', api.FoodViewSet)
router.register(r'food-inherit-field', api.FoodInheritFieldViewSet)
router.register(r'import-log', api.ImportLogViewSet)
@@ -178,7 +180,7 @@ for m in generic_models:
)
)
vue_models = [Food, Keyword, Unit, Supermarket, SupermarketCategory, Automation, UserFile, Step]
vue_models = [Food, Keyword, Unit, Supermarket, SupermarketCategory, Automation, UserFile, Step, CustomFilter]
for m in vue_models:
py_name = get_model_name(m)
url_name = py_name.replace('_', '-')

View File

@@ -42,18 +42,19 @@ from cookbook.helper.recipe_html_import import get_recipe_from_source
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch, old_search
from cookbook.helper.recipe_url_import import get_from_scraper
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
from cookbook.models import (Automation, BookmarkletImport, CookLog, Food, FoodInheritField,
ImportLog, Ingredient, Keyword, MealPlan, MealType, Recipe, RecipeBook,
RecipeBookEntry, ShareLink, ShoppingList, ShoppingListEntry,
ShoppingListRecipe, Step, Storage, Supermarket, SupermarketCategory,
SupermarketCategoryRelation, Sync, SyncLog, Unit, UserFile,
UserPreference, ViewLog)
from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilter, Food,
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
ShoppingListEntry, ShoppingListRecipe, Step, Storage, Supermarket,
SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, Unit,
UserFile, UserPreference, ViewLog)
from cookbook.provider.dropbox import Dropbox
from cookbook.provider.local import Local
from cookbook.provider.nextcloud import Nextcloud
from cookbook.schemas import FilterSchema, QueryParam, QueryParamAutoSchema, TreeSchema
from cookbook.serializer import (AutomationSerializer, BookmarkletImportSerializer,
CookLogSerializer, FoodInheritFieldSerializer, FoodSerializer,
CookLogSerializer, CustomFilterSerializer,
FoodInheritFieldSerializer, FoodSerializer,
FoodShoppingUpdateSerializer, ImportLogSerializer,
IngredientSerializer, KeywordSerializer, MealPlanSerializer,
MealTypeSerializer, RecipeBookEntrySerializer,
@@ -900,7 +901,19 @@ class AutomationViewSet(viewsets.ModelViewSet, StandardFilterMixin):
return super().get_queryset()
class CustomFilterViewSet(viewsets.ModelViewSet, StandardFilterMixin):
queryset = CustomFilter.objects
serializer_class = CustomFilterSerializer
permission_classes = [CustomIsOwner]
def get_queryset(self):
self.queryset = self.queryset.filter(Q(created_by=self.request.user) | Q(shared=self.request.user)).filter(
space=self.request.space).distinct()
return super().get_queryset()
# -------------- non django rest api views --------------------
def get_recipe_provider(recipe):
if recipe.storage.method == Storage.DROPBOX:
return Dropbox

View File

@@ -185,6 +185,22 @@ def automation(request):
)
@group_required('user')
def custom_filter(request):
# recipe-param is the name of the parameters used when filtering recipes by this attribute
# model-name is the models.js name of the model, probably ALL-CAPS
return render(
request,
'generic/model_template.html',
{
"title": _("Custom Filters"),
"config": {
'model': "CUSTOM_FILTER", # *REQUIRED* name of the model in models.js
}
}
)
@group_required('user')
def user_file(request):
try: