def test_add_existing_collaboration_to_meal_fails(self): ''' No new pending collaboration object should be created if the specified user is already a collaborator on the meal. Test steps: - create a meal - add an existing collaborator to the meal - send a patch request attempting to add the same collaborator to the meal - check that there is no new pending collaboration for that collaborator/meal combination ''' client = APIClient() meal_data = MealSerializer.get_meal_data(self.new_meal_data) collaborators_data = MealSerializer.get_collaborators( self.new_meal_data) meal = Meal(**meal_data) meal.save() meal.collaborators.set(collaborators_data) meal_id = meal.pk meal_owner = meal.owner.username user = User.objects.get(username=meal_owner) client.force_authenticate(user=user) url = "/meals/%d/" % meal_id client.patch(url, {"collaborators": [2]}, format="json") collaborator = User.objects.get(id=2) new_collaboration_exists = collaborator.new_shared_meals.filter( meal=meal).exists() self.assertFalse(new_collaboration_exists)
def test_filter_existing_collaborations_returns_true_if_no_collaboration_exists(self): new_meal = Meal(**self.new_meal_data) new_meal.save() collaborator = User.objects.get(id=self.pending_collaborators_data[0]) include_in_list = MealSerializer.filter_existing_collaborations(collaborator, new_meal) self.assertTrue(include_in_list)
def test_user_new_shared_meals(self): ''' Given a user, it should be possible to retrieve all of the pending meals other people have shared with the user by accessing the new_shared_meals property. Test steps: - create a new meal - send a patch request to add a collaborator to that meal - check that a new pending collaboration object for that meal is present on the collaborator's new_shared_meals property. ''' client = APIClient() data = { k: v for k, v in self.new_meal_data.items() if k != "collaborators" } meal = Meal(**data) meal.save() meal_id = meal.pk meal_owner = meal.owner.username user = User.objects.get(username=meal_owner) client.force_authenticate(user=user) url = "/meals/%d/" % meal_id client.patch(url, {"collaborators": [1]}, format="json") collaborator = User.objects.get(id=1) new_collaboration_exists = collaborator.new_shared_meals.filter( meal=meal).exists() self.assertTrue(new_collaboration_exists)
def test_add_collaboration_to_existing_meal(self): ''' Add collaborators to an existing meal. The collaborators should result in new pending collaborations being created. Test steps: - create a meal - send a patch request to add a collaborator to that meal - check that a new pending collaboration object exists for the collaborator/meal combination ''' client = APIClient() data = { k: v for k, v in self.new_meal_data.items() if k != "collaborators" } meal = Meal(**data) meal.save() meal_id = meal.pk meal_owner = meal.owner.username user = User.objects.get(username=meal_owner) client.force_authenticate(user=user) url = "/meals/%d/" % meal_id client.patch(url, {"collaborators": [1]}, format="json") collaborator = User.objects.get(id=1) self.assertIsNotNone( PendingCollaboration.objects.get(collaborator=collaborator, meal=meal))
def form_valid(self, form): for date, data in form.cleaned_data['data'].items(): try: meal = self.object.meal_set.get(date=date) except Meal.DoesNotExist: meal = Meal(person=self.object, date=date) meal.data = trim_meals_data(data) meal.save() return redirect(self.object.get_absolute_url())
def to_orm(self): meal = Meal(name=self.name) sub_meals = [ sub_meal.to_orm() if not isinstance(sub_meal, Meal) else sub_meal for sub_meal in self.sub_meals ] for sub_meal in sub_meals: sub_meal.parent = meal meal.sub_meals = sub_meals return meal
def test_filter_existing_collaborations_returns_false_if_collaboration_exists(self): new_meal = Meal(**self.new_meal_data) new_meal.save() owner = User.objects.get(id=4) for collaborator in self.pending_collaborators_data: user = User.objects.get(id=collaborator) PendingCollaboration(meal=new_meal, collaborator=user, owner=owner).save() new_meal.collaborators.set(self.existing_collaborators_data) collaborator = User.objects.get(id=self.existing_collaborators_data[0]) self.assertFalse(MealSerializer.filter_existing_collaborations(collaborator, new_meal))
def create(self, validated_data): collaborators = self.get_collaborators(validated_data) new_meal = self.get_meal_data(validated_data) meal = Meal(**new_meal) meal.save() pending_collaborations = self.create_pending_collaborations( collaborators, meal) for collaboration in pending_collaborations: collaboration.save() return meal
def add_meal(request, meal_option_id): form = MealForm(request.POST) meal_option = get_object_or_404(MealOption, pk=meal_option_id) # meal = get_object_or_404(Meal, pk=meal_option_id) if 'special' in request.POST: special = request.POST['special'] if special == 'on': special = True else: special = False if form.is_valid(): new_meal = Meal(name=request.POST['name'].lower(), user=request.user, meal_option=meal_option, special=special) new_meal.save() return redirect('meals:edit_meals')
def test_create_pending_collaborations(self): user = User() user.save() collaborators = (pipe | list | (filter, lambda x: user is x) | list | (lambda col: col[0:2]))(User.objects.all()) meal = Meal(name="test", taste=1, owner=user, difficulty=5) meal.save() pending_collaborations = MealSerializer.create_pending_collaborations(collaborators, meal) for collaboration in pending_collaborations: with self.subTest(collaboration=collaboration): self.assertEqual(collaboration, meal)
def test_delete_meal_succeeds(self): ''' An authenticated meal owner should be able to delete a meal. Test steps: - create a meal - send a request to delete the meal - check that response indicates success - check that the meal does not still exist in the db ''' client = APIClient() new_meal = Meal(**self.new_meal_data) new_meal.save() pk = new_meal.pk url = "/meals/%d/" % pk client.force_authenticate(user=new_meal.owner) response = client.delete(url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertFalse(Meal.objects.filter(pk=pk).exists())
def test_delete_meal_fails_if_not_owner(self): ''' An user authenticated as someone other than the meal owner should not be able to delete a meal. Test steps: - create a meal - authenticate as not the owner - send a request to delete the meal - check that response indicates failure - check that the meal still exists in the db ''' client = APIClient() new_meal = Meal(owner=User.objects.get(pk=2), **self.new_meal_data) new_meal.save() pk = new_meal.pk url = "/meals/%d/" % pk client.force_authenticate(user=User.objects.get(pk=1)) response = client.delete(url) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertTrue(Meal.objects.filter(pk=pk).exists())
def test_delete_meal_fails_if_not_logged_in(self): ''' An unauthenticated user should not be able to delete a meal. Test steps: - create a meal - send a request to delete the meal - check that response indicates failure - check that the meal still exists in the db ''' factory = APIRequestFactory() new_meal = Meal(**self.new_meal_data) new_meal.save() pk = new_meal.pk url = "/meals/%d/" % pk request = factory.delete(url) view = MealDetail.as_view() response = view(request) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) self.assertTrue(Meal.objects.filter(pk=pk).exists())
def test_update_ingredients_replaces_ingredients_list(self): ''' When a meal's ingredients are updated, the old ingredients list should be entirely replaced by the new one. Test steps: - create a meal with ingredients - send a request to update that meal's ingredients - check that the meal db object's incredients list reflects the update list. ''' new_meal_data = { "name": "test meal", "taste": 1, "difficulty": 1, "last_used": "2018-01-01", "used_count": 22, "notes": "test notes", "ingredients": ["sugar", "spice", "everything nice"] } new_meal = Meal(**new_meal_data) new_meal.save() meal_id = new_meal.pk updated_ingredients = {"ingredients": ["lemon", "lime"]} user = new_meal.owner client = APIClient() client.force_authenticate(user=user) url = "/meals/%d/" % meal_id client.patch(url, updated_ingredients, format="json") new_meal.refresh_from_db() self.assertListEqual(updated_ingredients["ingredients"], new_meal.ingredients)
def setUp(self): self.sample_meal_info = { "eater": "John", "name": "Burger", "description": "great!", "calories": 300, "meal_time": "2015-06-25T05:37:45.331352Z", } admin_group = Group(name="Admin") admin_group.save() self.admin_group = admin_group self.sample_password = "******" self.sample_user_credentials = { "email": "*****@*****.**", "username": "******", "password": self.sample_password, "calorie_target": 3500, } self.sample_admin_credentials = {'email': "*****@*****.**", 'username': "******", 'password': self.sample_password} self.sample_user = Account.objects.create_user(**self.sample_user_credentials) self.sample_admin = Account.objects.create_superuser(**self.sample_admin_credentials) self.sample_meal_info_2 = { "eater": self.sample_user, "name": "Pizza", "description": "good!", "calories": 200, "meal_time": "2015-06-25T05:37:45.331352Z", } self.sample_meal = Meal(**self.sample_meal_info_2) self.sample_meal.save() self.sample_meal_info_3 = { "eater": self.sample_admin, "name": "Burrito", "description": "good!", "calories": 200, "meal_time": "2015-07-25T05:37:45.331352Z", } self.sample_admin_meal = Meal(**self.sample_meal_info_3) self.sample_admin_meal.save()
def post(self, request, *args, **kwargs): name = request.POST.get('name', None) if not name: return HttpResponse(u'Não foi possível criar a pessoa') new_person = Person.objects.create(name=name) today = datetime.date.today() try: meal = Meal.objects.get(date=today) meal.washer = new_person meal.save() except Meal.DoesNotExist(): Meal.objects.create(date=today, ordered=True, washer=new_person) return HttpResponse(unicode(new_person.name))
def all_ids_must_exist(cls, sub_meals): ids = [meal for meal in sub_meals if isinstance(meal, int)] meals = Meal.select().where(Meal.id.in_(ids)) existing_ids = {meal.id for meal in meals} missing_ids = set(ids) - existing_ids if len(meals) != len(ids): raise ValueError(f"Meal ids {missing_ids} do not exist.") for meal in meals: # we need to make sure that sub-meals used in other meal-trees are not # stolen from there, so we make a copy by removing the id. meal.id = None return meals
def post(self, request, *args, **kwargs): meal = Meal() mealname = request.POST.get('meal_name') if mealname: meal.name = mealname mealtype = request.POST.get('meal_type') if mealtype: meal.kind = mealtype mealstarts = request.POST.get('meal_starts') if mealstarts: meal.starts = mealstarts mealends = request.POST.get('meal_ends') if mealends: meal.ends = mealends mealtimes = request.POST.get('meal_times') if mealtimes: meal.times = mealtimes mealopened = request.POST.get('meal_opened') if mealopened: meal.opened = (mealopened == 'opened') meal.save() messages.success(self.request, 'Meal added!') return redirect('meals_list')
def test_create_meal_with_ingredient(app_client): response = app_client.post( "/meals/meals/", json={ "name": "French toast", "ingredient": { "name": "Bread", "calories": 100 } }, ) assert response.status_code == status.HTTP_201_CREATED meal = Meal.get() assert all(( meal.name == "French toast", meal.ingredient.calories == 100, meal.ingredient.name == "Bread", ))
def generate_meal(): users = SystemUser.objects.all() for user in users: current_month = datetime.datetime.now().month current_year = datetime.datetime.now().year date_list = calendar.monthcalendar(current_year, current_month) dates = list(filter(lambda num: num != 0, combine(date_list))) for date in dates: meal = Meal( member=user, meal_date=datetime.date(current_year, current_month, date), breakfast=random.choice([0, 0.5, 1]), lunch=random.choice([0, 1, 2]), dinner=random.choice([0, 1, 2]), ) meal.save() meal_pk = str(meal.pk).zfill(4) meal.code = 'M-{0}'.format(meal_pk) meal.save() print('Meal generated successfully.')
def meal(request): context = {} context['lists_form'] = WbwListsForm() try: meal = context['meal'] = Meal.objects.get(completed=False) context['participation_form'] = ParticipationForm( wbw_list=meal.wbw_list) context['bystander_form'] = BystanderForm() context['form'] = MealForm(instance=meal) context['eaters'] = eaters = [] for p in meal.participants.all(): participation = Participation.objects.get(participant=p, wbw_list=meal.wbw_list) eaters.append({'participation': participation, 'participant': p}) for b in meal.bystanders.all(): participation = Participation.objects.get( participant=b.participant, wbw_list=meal.wbw_list) eaters.append({'participation': participation, 'bystander': b}) # add warning for eaters not in the wbw list context['warning_externals'] = settings.WARNING_EXTERNALS # these should probably be split into different view functions if 'update' in request.POST: context['form'] = form = MealForm(request.POST, instance=meal) if form.is_valid(): form.save() return redirect('meal') elif 'participate' in request.POST: pk = int(request.POST['participations']) participation = Participation.objects.get(pk=pk) meal.participants.add(participation.participant) meal.save() return redirect('meal') elif 'bystand' in request.POST: pk = int(request.POST['participations']) form = BystanderForm(request.POST) participation = Participation.objects.get(pk=pk) form.instance.participant = participation.participant form.save() meal.bystanders.add(form.instance) meal.save() return redirect('meal') elif 'unbystand' in request.POST: pk = int(request.POST['unbystand']) meal.bystanders.remove(Bystander.objects.get(pk=pk)) meal.save() return redirect('meal') elif 'unparticipate' in request.POST: pk = int(request.POST['unparticipate']) meal.participants.remove(Participant.objects.get(pk=pk)) meal.save() return redirect('meal') elif 'abort' in request.POST: meal.delete() return redirect('meal') elif 'finalise' in request.POST: context['form'] = form = MealForm(request.POST, instance=meal) if form.is_valid(): form.save() errors = False # surely there's a more elegant way to do this if not meal.payer: context['form'].add_error('payer', "Wie gaat dit geintje betalen?.") errors = True if not meal.price > 0: context['form'].add_error( 'price', "Er moet wel iets te betalen vallen.") errors = True if not meal.participants.all() and not meal.bystanders.all(): messages.error(request, "Zonder deelnemers valt er niks te verwerken.") errors = True if not errors: session, response = _create_wbw_session() date = datetime.strftime(localtime(meal.date), "%Y-%m-%d") desc = [] for b in meal.bystanders.all(): part = Participation.objects.get(participant=b.participant, wbw_list=meal.wbw_list) desc.append("{} via {}".format(b.name, part.name)) desc = "{} ({})".format(meal.description, ', '.join(desc)) payload = { 'expense': { 'payed_by_id': meal.payer.wbw_id, 'name': desc, 'payed_on': date, 'amount': 0, 'shares_attributes': [] } } participants = list( chain(meal.participants.all(), [b.participant for b in meal.bystanders.all()])) amount_per_p = math.ceil(meal.price / len(participants)) for p in participants: payload['expense']['shares_attributes'].append({ 'member_id': p.wbw_id, 'multiplier': 1, 'amount': amount_per_p }) # Wiebetaaltwat does not like to share beyond decimals # so we ensure that the total amount is the sum of parts. payload['expense']['amount'] += amount_per_p # We must remove duplicate shares shares = {} for share in list(payload['expense']['shares_attributes']): if share['member_id'] not in shares: shares[share['member_id']] = share else: shares[share['member_id']]['multiplier'] += 1 # Since multiplier and amount seem to be unrelated.. shares[share['member_id']]['amount'] += amount_per_p payload['expense']['shares_attributes'].remove(share) url = ('https://api.wiebetaaltwat.nl/api/lists/{}/expenses'. format(meal.wbw_list.list_id)) session.post(url, json=payload, headers={'Accept-Version': '1'}, cookies=response.cookies) meal.completed = True meal.save() messages.success(request, "De maaltijd is verwerkt!") return redirect('meal') except Meal.DoesNotExist: if 'startmeal' in request.POST: form = WbwListsForm(request.POST) if form.is_valid(): wbw_list = Wbw_list.objects.get(pk=form.data['wbw_lists']) Meal(wbw_list=wbw_list).save() return redirect('meal') return render(request, 'meals/meal.html', context)
def save(self): meal = self.to_orm() existing_, new_ = partition(self._exists, meal.sub_meals) Meal.bulk_update(list(existing_), fields=["parent"]) Meal.bulk_create(list(new_) + [meal]) return meal
class MealsAPITest(APITestCase): """ Functional tests of the REST functionality of meals API. """ def setUp(self): self.sample_meal_info = { "eater": "John", "name": "Burger", "description": "great!", "calories": 300, "meal_time": "2015-06-25T05:37:45.331352Z", } admin_group = Group(name="Admin") admin_group.save() self.admin_group = admin_group self.sample_password = "******" self.sample_user_credentials = { "email": "*****@*****.**", "username": "******", "password": self.sample_password, "calorie_target": 3500, } self.sample_admin_credentials = {'email': "*****@*****.**", 'username': "******", 'password': self.sample_password} self.sample_user = Account.objects.create_user(**self.sample_user_credentials) self.sample_admin = Account.objects.create_superuser(**self.sample_admin_credentials) self.sample_meal_info_2 = { "eater": self.sample_user, "name": "Pizza", "description": "good!", "calories": 200, "meal_time": "2015-06-25T05:37:45.331352Z", } self.sample_meal = Meal(**self.sample_meal_info_2) self.sample_meal.save() self.sample_meal_info_3 = { "eater": self.sample_admin, "name": "Burrito", "description": "good!", "calories": 200, "meal_time": "2015-07-25T05:37:45.331352Z", } self.sample_admin_meal = Meal(**self.sample_meal_info_3) self.sample_admin_meal.save() def test_logged_out_user_cannot_create_meal(self): url = reverse("meals-list") response = self.client.post(url, self.sample_meal_info) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_logged_out_user_cannot_see_meal(self): url = reverse("meals-detail", args=(1,)) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_logged_out_user_cannot_update_meal(self): url = reverse("meals-detail", args=(1,)) response = self.client.put(url, self.sample_meal_info) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_logged_out_user_cannot_delete_meal(self): url = reverse("meals-detail", args=(1,)) response = self.client.delete(url) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_create_meal_from_valid_data(self): url = reverse("meals-list") self.client.login(username=self.sample_user.username, password=self.sample_password) response = self.client.post(url, self.sample_meal_info) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.content, '{"id":3,"eater":{"id":1,"email":"*****@*****.**","username":"******","calorie_target":2000,"is_admin":false},"name":"Burger","description":"great!","calories":300,"meal_time":"2015-06-25T05:37:45.331352Z"}') def test_create_meal_from_invalid_data(self): invalid_meal = { "name": 500, "meal_time": 500, "calories": "beans" } url = reverse("meals-list") self.client.login(username=self.sample_user.username, password=self.sample_password) response = self.client.post(url, invalid_meal) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_update_meal_with_valid_data(self): self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-detail", args=(1,)) response = self.client.put(url, self.sample_meal_info) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.content, '{"id":1,"eater":{"id":1,"email":"*****@*****.**","username":"******","calorie_target":2000,"is_admin":false},"name":"Burger","description":"great!","calories":300,"meal_time":"2015-06-25T05:37:45.331352Z"}') def test_update_meal_with_invalid_data(self): invalid_meal = { "name": 500, "meal_time": 500, "calories": "beans" } self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-detail", args=(1,)) response = self.client.put(url, invalid_meal) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_can_view_own_meal_detail(self): self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-detail", args=(1,)) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.content, '{"id":1,"eater":{"id":1,"email":"*****@*****.**","username":"******","calorie_target":2000,"is_admin":false},"name":"Pizza","description":"good!","calories":200,"meal_time":"2015-06-25T05:37:45.331352Z"}') def test_delete_meal(self): self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-detail", args=(1,)) response = self.client.delete(url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_non_admin_can_only_create_own_meal(self): friends_meal = { "eater": self.sample_admin, "name": "Pizza", "description": "good!", "calories": 200, "meal_time": "2015-06-25T05:37:45.331352Z", } url = reverse("meals-list") self.client.login(username=self.sample_user.username, password=self.sample_password) response = self.client.post(url, friends_meal) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.content, '{"id":3,"eater":{"id":1,"email":"*****@*****.**","username":"******","calorie_target":2000,"is_admin":false},"name":"Pizza","description":"good!","calories":200,"meal_time":"2015-06-25T05:37:45.331352Z"}') def test_non_admin_can_only_edit_own_meal(self): self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-detail", args=(2,)) response = self.client.put(url, self.sample_meal_info) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_non_admin_can_only_delete_own_meal(self): self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-detail", args=(2,)) response = self.client.delete(url) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_admin_can_edit_any_meal(self): self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-detail", args=(1,)) response = self.client.put(url, self.sample_meal_info) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.content, '{"id":1,"eater":{"id":1,"email":"*****@*****.**","username":"******","calorie_target":2000,"is_admin":false},"name":"Burger","description":"great!","calories":300,"meal_time":"2015-06-25T05:37:45.331352Z"}') def test_admin_can_delete_any_meal(self): self.client.login(username=self.sample_admin.username, password=self.sample_password) url = reverse("meals-detail", args=(1,)) response = self.client.delete(url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_admin_sees_all_meals(self): self.client.login(username=self.sample_admin.username, password=self.sample_password) url = reverse("meals-list") response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data), 2) def test_non_admin_sees_only_own_meals(self): self.client.login(username=self.sample_user.username, password=self.sample_password) url = reverse("meals-list") response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data), 1) def test_logged_out_user_sees_no_meals(self): url = reverse("meals-list") response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_meals_ordered_by_meal_time(self): self.client.login(username=self.sample_admin.username, password=self.sample_password) url = reverse("meals-list") response = self.client.get(url) self.assertEqual(response.data[0]["name"], "Burrito")
def to_orm(self): return Meal(name=self.name, ingredient=self.ingredient.to_orm())
def get_meals(): return list(Meal.select())