Fix after rebase

This commit is contained in:
smilerz 2021-07-29 16:38:33 -05:00
parent 89ec549dac
commit 2f91c2f86e
18 changed files with 4375 additions and 4556 deletions

View File

@ -18,6 +18,8 @@ from .models import (Comment, CookLog, Food, Ingredient, InviteLink, Keyword,
from cookbook.managers import DICTIONARY
from cookbook.managers import DICTIONARY
class CustomUserAdmin(UserAdmin):
def has_add_permission(self, request, obj=None):

View File

@ -35,10 +35,12 @@ def search_recipes(request, queryset, params):
return queryset.filter(pk__in=last_viewed_recipes[len(last_viewed_recipes) - min(len(last_viewed_recipes), search_last_viewed):])
queryset = queryset.annotate(
new_recipe=Case(When(
created_at__gte=(datetime.now() - timedelta(days=7)), then=Value(100)),
default=Value(0), )).order_by('-new_recipe', 'name')
if search_new == 'true':
queryset = queryset.annotate(
new_recipe=Case(When(created_at__gte=(datetime.now() - timedelta(days=7)), then=Value(100)),
default=Value(0), )).order_by('-new_recipe', 'name')
else:
queryset = queryset.order_by('name')
search_type = search_prefs.search or 'plain'
search_sort = None
@ -148,12 +150,6 @@ def search_recipes(request, queryset, params):
elif search_sort == 'rank':
queryset = queryset.order_by('-rank')
# kw = Keyword.objects.filter(recipe__in=queryset).annotate(kw_count=Count('recipe'))
# Keyword.get_annotated_list_qs(Keyword.objects.filter(id__in=[item.id for k in kw for item in k.get_ancestors_and_self()]))
# print(time.time()-start, len(queryset), len(kw))
# Keyword.get_annotated_list_qs(
# Keyword.objects.filter(recipe__in=queryset).annotate(kw_count=Count('recipe'))
# | Keyword.objects.all().filter(id__in=set([k.parent for k in Keyword.objects.filter(recipe__in=queryset).annotate(kw_count=Count('recipe'))])))
return queryset

View File

@ -27,7 +27,7 @@ def backwards(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0140_userpreference_created_at'),
('cookbook', '0145_alter_userpreference_use_fractions'),
]
operations = [

View File

@ -422,6 +422,7 @@ class Step(ExportModelOperationsMixin('step'), models.Model, PermissionModelMixi
file = models.ForeignKey('UserFile', on_delete=models.PROTECT, null=True, blank=True)
show_as_header = models.BooleanField(default=True)
search_vector = SearchVectorField(null=True)
step_recipe = models.ForeignKey('Recipe', default=None, blank=True, null=True, on_delete=models.PROTECT)
space = models.ForeignKey(Space, on_delete=models.CASCADE)
objects = ScopedManager(space='space')
@ -840,42 +841,11 @@ class UserFile(ExportModelOperationsMixin('user_files'), models.Model, Permissio
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return _(self.name)
objects = ScopedManager(space='space')
space = models.ForeignKey(Space, on_delete=models.CASCADE)
@staticmethod
def get_name(self):
return _(self.name)
def allSearchFields():
return SearchFields.objects.values_list('id')
def nameSearchField():
return [SearchFields.objects.get(name='Name').id]
class SearchPreference(models.Model, PermissionModelMixin):
# Search Style (validation parsleyjs.org)
# phrase or plain or raw (websearch and trigrams are mutually exclusive)
SIMPLE = 'plain'
PHRASE = 'phrase'
WEB = 'websearch'
RAW = 'raw'
SEARCH_STYLE = (
(SIMPLE, _('Simple')),
(PHRASE, _('Phrase')),
(WEB, _('Web')),
(RAW, _('Raw'))
)
user = AutoOneToOneField(User, on_delete=models.CASCADE, primary_key=True)
search = models.CharField(choices=SEARCH_STYLE, max_length=32, default=SIMPLE)
lookup = models.BooleanField(default=False)
unaccent = models.ManyToManyField(SearchFields, related_name="unaccent_fields", blank=True, default=allSearchFields)
icontains = models.ManyToManyField(SearchFields, related_name="icontains_fields", blank=True, default=nameSearchField)
istartswith = models.ManyToManyField(SearchFields, related_name="istartswith_fields", blank=True)
trigram = models.ManyToManyField(SearchFields, related_name="trigram_fields", blank=True)
fulltext = models.ManyToManyField(SearchFields, related_name="fulltext_fields", blank=True)
def save(self, *args, **kwargs):
if hasattr(self.file, 'file') and isinstance(self.file.file, UploadedFile) or isinstance(self.file.file, InMemoryUploadedFile):
self.file.name = f'{uuid.uuid4()}' + pathlib.Path(self.file.name).suffix
self.file_size_kb = round(self.file.size / 1000)
super(UserFile, self).save(*args, **kwargs)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -322,9 +322,17 @@ class SupermarketCategoryViewSet(viewsets.ModelViewSet, StandardFilterMixin):
return super().get_queryset()
class KeywordViewSet(viewsets.ModelViewSet, TreeMixin):
# TODO check if fuzzyfilter is conflicting - may also need to create 'tree filter' mixin
class SupermarketCategoryRelationViewSet(viewsets.ModelViewSet, StandardFilterMixin):
queryset = SupermarketCategoryRelation.objects
serializer_class = SupermarketCategoryRelationSerializer
permission_classes = [CustomIsUser]
def get_queryset(self):
self.queryset = self.queryset.filter(supermarket__space=self.request.space)
return super().get_queryset()
class KeywordViewSet(viewsets.ModelViewSet, StandardFilterMixin):
queryset = Keyword.objects
model = Keyword
serializer_class = KeywordSerializer
@ -439,6 +447,67 @@ class RecipePagination(PageNumberPagination):
max_page_size = 100
# TODO move to separate class to cleanup
class RecipeSchema(AutoSchema):
def get_path_parameters(self, path, method):
if not is_list_view(path, method, self.view):
return super(RecipeSchema, self).get_path_parameters(path, method)
parameters = super().get_path_parameters(path, method)
parameters.append({
"name": 'query', "in": "query", "required": False,
"description": 'Query string matched (fuzzy) against recipe name. In the future also fulltext search.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'keywords', "in": "query", "required": False,
"description": 'Id of keyword a recipe should have. For multiple repeat parameter.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'foods', "in": "query", "required": False,
"description": 'Id of food a recipe should have. For multiple repeat parameter.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'books', "in": "query", "required": False,
"description": 'Id of book a recipe should have. For multiple repeat parameter.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'keywords_or', "in": "query", "required": False,
"description": 'If recipe should have all (AND) or any (OR) of the provided keywords.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'foods_or', "in": "query", "required": False,
"description": 'If recipe should have all (AND) or any (OR) any of the provided foods.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'books_or', "in": "query", "required": False,
"description": 'If recipe should be in all (AND) or any (OR) any of the provided books.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'internal', "in": "query", "required": False,
"description": 'true or false. If only internal recipes should be returned or not.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'random', "in": "query", "required": False,
"description": 'true or false. returns the results in randomized order.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'new', "in": "query", "required": False,
"description": 'true or false. returns new results first in search results',
'schema': {'type': 'string', },
})
return parameters
class RecipeViewSet(viewsets.ModelViewSet):
queryset = Recipe.objects
serializer_class = RecipeSerializer

View File

@ -122,11 +122,6 @@
<a :href="resolveDjangoUrl('view_settings') + '#search'">{{ $t('Advanced Search Settings') }}</a>
</div>
</div>
<div class="row" style="margin-top: 1vh">
<div class="col-12">
<a :href="resolveDjangoUrl('view_settings') + '#search'">{{ $t('Advanced Search Settings') }}</a>
</div>
</div>
<div class="row" style="margin-top: 1vh">
<div class="col-12" style="text-align: right">
<b-button size="sm" variant="secondary" style="margin-right:8px"

View File

@ -6,8 +6,7 @@
<b-card-img-lazy style="height: 15vh; object-fit: cover" class="" :src=recipe_image
v-bind:alt="$t('Recipe_Image')"
top></b-card-img-lazy>
<div class="h-100 d-flex flex-column justify-content-right"
<div class="card-img-overlay h-100 d-flex flex-column justify-content-right"
style="float:right; text-align: right; padding-top: 10px; padding-right: 5px">
<a>
<recipe-context-menu :recipe="recipe" style="float:right" v-if="recipe !== null"></recipe-context-menu>
@ -120,4 +119,4 @@ export default {
<style scoped>
</style>
</style>

View File

@ -56,6 +56,7 @@
"Rating": "Rating",
"Close": "Close",
"Cancel": "Cancel",
"Link": "Link",
"Add": "Add",
"New": "New",
"Success": "Success",
@ -85,6 +86,7 @@
"or": "or",
"and": "and",
"Information": "Information",
"Advanced Search Settings": "Advanced Search Settings",
"View": "View",
"Recipes": "Recipes",
"Move": "Move",
@ -98,4 +100,4 @@
"Advanced Search Settings": "Advanced Search Settings",
"Download": "Download",
"Root": "Root"
}
}

View File

@ -8082,8 +8082,8 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listRecipes(query?: string, keywords?: string, foods?: string, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2001>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listRecipes(query, keywords, foods, books, keywordsOr, foodsOr, booksOr, internal, random, page, pageSize, options);
async listRecipes(query?: string, keywords?: string, foods?: string, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, _new?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse200>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listRecipes(query, keywords, foods, books, keywordsOr, foodsOr, booksOr, internal, random, _new, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
@ -9596,8 +9596,8 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listRecipes(query?: string, keywords?: string, foods?: string, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2001> {
return localVarFp.listRecipes(query, keywords, foods, books, keywordsOr, foodsOr, booksOr, internal, random, page, pageSize, options).then((request) => request(axios, basePath));
listRecipes(query?: string, keywords?: string, foods?: string, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, _new?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse200> {
return localVarFp.listRecipes(query, keywords, foods, books, keywordsOr, foodsOr, booksOr, internal, random, _new, page, pageSize, options).then((request) => request(axios, basePath));
},
/**
*

File diff suppressed because it is too large Load Diff