def ready(self): # post_save signal is only necessary if using full-text search on postgres if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']: import cookbook.signals # noqa if not settings.DISABLE_TREE_FIX_STARTUP: # when starting up run fix_tree to: # a) make sure that nodes are sorted when switching between sort modes # b) fix problems, if any, with tree consistency with scopes_disabled(): try: from cookbook.models import Keyword, Food Keyword.fix_tree(fix_paths=True) Food.fix_tree(fix_paths=True) except OperationalError: if DEBUG: traceback.print_exc() pass # if model does not exist there is no need to fix it except ProgrammingError: if DEBUG: traceback.print_exc() pass # if migration has not been run database cannot be fixed yet except Exception: if DEBUG: traceback.print_exc() pass # dont break startup just because fix could not run, need to investigate cases when this happens
def test_move(u1_s1, obj_tree_1, obj_2, obj_3, space_1): with scope(space=space_1): parent = obj_tree_1.get_parent() child = obj_tree_1.get_descendants()[0] assert parent.get_num_children() == 1 assert parent.get_descendant_count() == 2 assert Food.get_root_nodes().filter(space=space_1).count() == 2 url = reverse(MOVE_URL, args=[obj_tree_1.id, obj_2.id]) # move child to new parent, only HTTP put method should work r = u1_s1.get(url) assert r.status_code == 405 r = u1_s1.post(url) assert r.status_code == 405 r = u1_s1.delete(url) assert r.status_code == 405 r = u1_s1.put(url) assert r.status_code == 200 with scopes_disabled(): # django-treebeard bypasses django ORM so object needs retrieved again parent = Food.objects.get(pk=parent.id) obj_2 = Food.objects.get(pk=obj_2.id) assert parent.get_num_children() == 0 assert parent.get_descendant_count() == 0 assert obj_2.get_num_children() == 1 assert obj_2.get_descendant_count() == 2 # run diagnostic to find problems - none should be found with scopes_disabled(): assert Food.find_problems() == ([], [], [], [], [])
def test_merge( u1_s1, obj_1, obj_2, obj_3, ing_1_s1, ing_2_s1, ing_3_s2, sle_1_s1, sle_2_s1, sle_3_s2, space_1 ): with scopes_disabled(): assert Unit.objects.filter(space=space_1).count() == 2 assert obj_1.ingredient_set.count() == 1 assert obj_2.ingredient_set.count() == 1 assert obj_3.ingredient_set.count() == 1 assert obj_1.shoppinglistentry_set.count() == 1 assert obj_2.shoppinglistentry_set.count() == 1 assert obj_3.shoppinglistentry_set.count() == 1 # merge Unit with ingredient/shopping list entry with another Unit, only HTTP put method should work url = reverse(MERGE_URL, args=[obj_1.id, obj_2.id]) r = u1_s1.get(url) assert r.status_code == 405 r = u1_s1.post(url) assert r.status_code == 405 r = u1_s1.delete(url) assert r.status_code == 405 r = u1_s1.put(url) assert r.status_code == 200 with scopes_disabled(): assert Unit.objects.filter(pk=obj_1.id).count() == 0 assert obj_2.ingredient_set.count() == 2 assert obj_3.ingredient_set.count() == 1 assert obj_2.shoppinglistentry_set.count() == 2 assert obj_3.shoppinglistentry_set.count() == 1 # attempt to merge with non-existent parent r = u1_s1.put( reverse(MERGE_URL, args=[obj_2.id, 9999]) ) assert r.status_code == 404 # attempt to move to wrong space r = u1_s1.put( reverse(MERGE_URL, args=[obj_2.id, obj_3.id]) ) assert r.status_code == 404 # attempt to merge with self r = u1_s1.put( reverse(MERGE_URL, args=[obj_2.id, obj_2.id]) ) assert r.status_code == 403 # run diagnostic to find problems - none should be found with scopes_disabled(): assert Food.find_problems() == ([], [], [], [], [])
def test_move(u1_s1, obj_1, obj_1_1, obj_1_1_1, obj_2, obj_3, space_1): url = reverse(MOVE_URL, args=[obj_1_1.id, obj_2.id]) with scopes_disabled(): assert obj_1.get_num_children() == 1 assert obj_1.get_descendant_count() == 2 assert Food.get_root_nodes().filter(space=space_1).count() == 2 # move child to new parent, only HTTP put method should work r = u1_s1.get(url) assert r.status_code == 405 r = u1_s1.post(url) assert r.status_code == 405 r = u1_s1.delete(url) assert r.status_code == 405 r = u1_s1.put(url) assert r.status_code == 200 with scopes_disabled(): # django-treebeard bypasses django ORM so object needs retrieved again obj_1 = Food.objects.get(pk=obj_1.id) obj_2 = Food.objects.get(pk=obj_2.id) assert obj_1.get_num_children() == 0 assert obj_1.get_descendant_count() == 0 assert obj_2.get_num_children() == 1 assert obj_2.get_descendant_count() == 2 # move child to root r = u1_s1.put(reverse(MOVE_URL, args=[obj_1_1.id, 0])) assert r.status_code == 200 with scopes_disabled(): assert Food.get_root_nodes().filter(space=space_1).count() == 3 # attempt to move to non-existent parent r = u1_s1.put(reverse(MOVE_URL, args=[obj_1.id, 9999])) assert r.status_code == 404 # attempt to move to wrong space r = u1_s1.put(reverse(MOVE_URL, args=[obj_1_1.id, obj_3.id])) assert r.status_code == 404 # run diagnostic to find problems - none should be found with scopes_disabled(): assert Food.find_problems() == ([], [], [], [], [])
def test_merge(u1_s1, obj_tree_1, obj_1, obj_3, space_1): with scope(space=space_1): parent = obj_tree_1.get_parent() child = obj_tree_1.get_descendants()[0] assert parent.get_num_children() == 1 assert parent.get_descendant_count() == 2 assert Food.get_root_nodes().filter(space=space_1).count() == 2 assert Food.objects.count() == 4 # merge food with no children with another food, only HTTP put method should work url = reverse(MERGE_URL, args=[child.id, obj_tree_1.id]) r = u1_s1.get(url) assert r.status_code == 405 r = u1_s1.post(url) assert r.status_code == 405 r = u1_s1.delete(url) assert r.status_code == 405 r = u1_s1.put(url) assert r.status_code == 200 with scope(space=space_1): # django-treebeard bypasses django ORM so object needs retrieved again with pytest.raises(Food.DoesNotExist): Food.objects.get(pk=child.id) obj_tree_1 = Food.objects.get(pk=obj_tree_1.id) assert parent.get_num_children() == 1 assert parent.get_descendant_count() == 1 # merge food with children with another food r = u1_s1.put(reverse(MERGE_URL, args=[parent.id, obj_1.id])) assert r.status_code == 200 with scope(space=space_1): # django-treebeard bypasses django ORM so object needs retrieved again with pytest.raises(Food.DoesNotExist): Food.objects.get(pk=parent.id) obj_1 = Food.objects.get(pk=obj_1.id) assert obj_1.get_num_children() == 1 assert obj_1.get_descendant_count() == 1 # run diagnostic to find problems - none should be found with scopes_disabled(): assert Food.find_problems() == ([], [], [], [], [])
def space(request): space_users = UserPreference.objects.filter(space=request.space).all() counts = Object() counts.recipes = Recipe.objects.filter(space=request.space).count() counts.keywords = Keyword.objects.filter(space=request.space).count() counts.recipe_import = RecipeImport.objects.filter(space=request.space).count() counts.units = Unit.objects.filter(space=request.space).count() counts.ingredients = Food.objects.filter(space=request.space).count() counts.comments = Comment.objects.filter(recipe__space=request.space).count() counts.recipes_internal = Recipe.objects.filter(internal=True, space=request.space).count() counts.recipes_external = counts.recipes - counts.recipes_internal counts.recipes_no_keyword = Recipe.objects.filter(keywords=None, space=request.space).count() invite_links = InviteLinkTable( InviteLink.objects.filter(valid_until__gte=datetime.today(), used_by=None, space=request.space).all()) RequestConfig(request, paginate={'per_page': 25}).configure(invite_links) space_form = SpacePreferenceForm(instance=request.space) space_form.base_fields['food_inherit'].queryset = Food.inheritable_fields if request.method == "POST" and 'space_form' in request.POST: form = SpacePreferenceForm(request.POST, prefix='space') if form.is_valid(): request.space.food_inherit.set(form.cleaned_data['food_inherit']) request.space.show_facet_count = form.cleaned_data['show_facet_count'] request.space.save() if form.cleaned_data['reset_food_inherit']: Food.reset_inheritance(space=request.space) return render(request, 'space.html', { 'space_users': space_users, 'counts': counts, 'invite_links': invite_links, 'space_form': space_form })
def test_delete(u1_s1, u1_s2, obj_1, obj_1_1, obj_1_1_1): with scopes_disabled(): assert Food.objects.count() == 3 r = u1_s2.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 404 with scopes_disabled(): assert Food.objects.count() == 3 r = u1_s1.delete(reverse(DETAIL_URL, args={obj_1_1.id})) assert r.status_code == 204 with scopes_disabled(): assert Food.objects.count() == 1 assert Food.find_problems() == ([], [], [], [], [])
def test_delete(u1_s1, u1_s2, obj_1, obj_tree_1): with scopes_disabled(): assert Food.objects.count() == 4 r = u1_s2.delete(reverse(DETAIL_URL, args={obj_1.id})) assert r.status_code == 404 with scopes_disabled(): assert Food.objects.count() == 4 # should delete self and child, leaving parent r = u1_s1.delete(reverse(DETAIL_URL, args={obj_tree_1.id})) assert r.status_code == 204 with scopes_disabled(): assert Food.objects.count() == 2 assert Food.find_problems() == ([], [], [], [], [])
def test_move_errors(u1_s1, obj_tree_1, obj_3, space_1): with scope(space=space_1): parent = obj_tree_1.get_parent() child = obj_tree_1.get_descendants()[0] # move child to root r = u1_s1.put(reverse(MOVE_URL, args=[obj_tree_1.id, 0])) assert r.status_code == 200 with scopes_disabled(): assert Food.get_root_nodes().filter(space=space_1).count() == 2 # attempt to move to non-existent parent r = u1_s1.put(reverse(MOVE_URL, args=[parent.id, 9999])) assert r.status_code == 404 # attempt to move non-existent mode to parent r = u1_s1.put(reverse(MOVE_URL, args=[9999, parent.id])) assert r.status_code == 404 # attempt to move to wrong space r = u1_s1.put(reverse(MOVE_URL, args=[obj_tree_1.id, obj_3.id])) assert r.status_code == 404
reset_inherit = self.initial_data.get('reset_inherit', False) if not onhand is None: shared_users = [user := self.context['request'].user] + list( user.userpreference.shopping_share.all()) if onhand: validated_data['onhand_users'] = list( self.instance.onhand_users.all()) + shared_users else: validated_data['onhand_users'] = list( set(self.instance.onhand_users.all()) - set(shared_users)) # update before resetting inheritance saved_instance = super(FoodSerializer, self).update(instance, validated_data) if reset_inherit and (r := self.context.get('request', None)): Food.reset_inheritance(food=saved_instance, space=r.space) return saved_instance class Meta: model = Food fields = ('id', 'name', 'description', 'shopping', 'recipe', 'food_onhand', 'supermarket_category', 'image', 'parent', 'numchild', 'numrecipe', 'inherit_fields', 'full_name', 'ignore_shopping', 'substitute', 'substitute_siblings', 'substitute_children', 'substitute_onhand', 'child_inherit_fields') read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe') class IngredientSimpleSerializer(WritableNestedModelSerializer): food = FoodSimpleSerializer(allow_null=True)
def test_merge(u1_s1, obj_1, obj_1_1, obj_1_1_1, obj_2, obj_3, ing_1_s1, ing_2_s1, ing_3_s2, ing_1_1_s1, sle_1_s1, sle_2_s1, sle_3_s2, sle_1_1_s1, space_1): with scopes_disabled(): assert obj_1.get_num_children() == 1 assert obj_1.get_descendant_count() == 2 assert Food.get_root_nodes().filter(space=space_1).count() == 2 assert Food.objects.filter(space=space_1).count() == 4 assert obj_1.ingredient_set.count() == 1 assert obj_2.ingredient_set.count() == 1 assert obj_3.ingredient_set.count() == 1 assert obj_1_1.ingredient_set.count() == 1 assert obj_1_1_1.ingredient_set.count() == 0 assert obj_1.shoppinglistentry_set.count() == 1 assert obj_2.shoppinglistentry_set.count() == 1 assert obj_3.shoppinglistentry_set.count() == 1 assert obj_1_1.shoppinglistentry_set.count() == 1 assert obj_1_1_1.shoppinglistentry_set.count() == 0 # merge food with no children and no ingredient/shopping list entry with another food, only HTTP put method should work url = reverse(MERGE_URL, args=[obj_1_1_1.id, obj_2.id]) r = u1_s1.get(url) assert r.status_code == 405 r = u1_s1.post(url) assert r.status_code == 405 r = u1_s1.delete(url) assert r.status_code == 405 r = u1_s1.put(url) assert r.status_code == 200 with scopes_disabled(): # django-treebeard bypasses django ORM so object needs retrieved again obj_1 = Food.objects.get(pk=obj_1.id) obj_2 = Food.objects.get(pk=obj_2.id) assert Food.objects.filter(pk=obj_1_1_1.id).count() == 0 assert obj_1.get_num_children() == 1 assert obj_1.get_descendant_count() == 1 assert obj_2.get_num_children() == 0 assert obj_2.get_descendant_count() == 0 assert obj_1.ingredient_set.count() == 1 assert obj_2.ingredient_set.count() == 1 assert obj_3.ingredient_set.count() == 1 assert obj_1_1.ingredient_set.count() == 1 assert obj_1.shoppinglistentry_set.count() == 1 assert obj_2.shoppinglistentry_set.count() == 1 assert obj_3.shoppinglistentry_set.count() == 1 assert obj_1_1.shoppinglistentry_set.count() == 1 # merge food (with connected ingredient/shoppinglistentry) with children to another food r = u1_s1.put(reverse(MERGE_URL, args=[obj_1.id, obj_2.id])) assert r.status_code == 200 with scopes_disabled(): # django-treebeard bypasses django ORM so object needs retrieved again obj_2 = Food.objects.get(pk=obj_2.id) assert Food.objects.filter(pk=obj_1.id).count() == 0 assert obj_2.get_num_children() == 1 assert obj_2.get_descendant_count() == 1 assert obj_2.ingredient_set.count() == 2 assert obj_3.ingredient_set.count() == 1 assert obj_1_1.ingredient_set.count() == 1 assert obj_2.shoppinglistentry_set.count() == 2 assert obj_3.shoppinglistentry_set.count() == 1 assert obj_1_1.shoppinglistentry_set.count() == 1 # attempt to merge with non-existent parent r = u1_s1.put(reverse(MERGE_URL, args=[obj_1_1.id, 9999])) assert r.status_code == 404 # attempt to move to wrong space r = u1_s1.put(reverse(MERGE_URL, args=[obj_2.id, obj_3.id])) assert r.status_code == 404 # attempt to merge with child r = u1_s1.put(reverse(MERGE_URL, args=[obj_2.id, obj_1_1.id])) assert r.status_code == 403 # attempt to merge with self r = u1_s1.put(reverse(MERGE_URL, args=[obj_2.id, obj_2.id])) assert r.status_code == 403 # run diagnostic to find problems - none should be found with scopes_disabled(): assert Food.find_problems() == ([], [], [], [], [])