Skip to content

Commit ac41cb5

Browse files
authored
Merge pull request #219 from jeffshek/supplement-stack-views
Add Supplement Stack Functionality to Log Views
2 parents 9b7a0bb + b51aa4a commit ac41cb5

File tree

3 files changed

+130
-8
lines changed

3 files changed

+130
-8
lines changed

open/core/betterself/serializers/supplement_log_serializers.py

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.core.exceptions import ObjectDoesNotExist
12
from rest_framework.exceptions import ValidationError
23
from rest_framework.fields import (
34
UUIDField,
@@ -11,6 +12,7 @@
1112
from open.core.betterself.constants import INPUT_SOURCES_TUPLES, WEB_INPUT_SOURCE
1213
from open.core.betterself.models.supplement import Supplement
1314
from open.core.betterself.models.supplement_log import SupplementLog
15+
from open.core.betterself.models.supplement_stack import SupplementStack
1416
from open.core.betterself.serializers.mixins import (
1517
BaseCreateUpdateSerializer,
1618
BaseModelReadSerializer,
@@ -61,7 +63,10 @@ class SupplementLogCreateUpdateSerializer(BaseCreateUpdateSerializer):
6163
user = HiddenField(default=CurrentUserDefault())
6264
uuid = UUIDField(required=False, read_only=True)
6365
notes = CharField(
64-
default="", trim_whitespace=True, required=False, allow_blank=True,
66+
default="",
67+
trim_whitespace=True,
68+
required=False,
69+
allow_blank=True,
6570
)
6671
quantity = DecimalField(decimal_places=4, max_digits=10, default=1)
6772
source = ChoiceField(INPUT_SOURCES_TUPLES, default=WEB_INPUT_SOURCE)
@@ -81,24 +86,84 @@ class Meta:
8186

8287
def validate_supplement_uuid(self, value):
8388
user = self.context["request"].user
84-
validate_model_uuid(Supplement, uuid=value, user=user)
89+
try:
90+
validate_model_uuid(Supplement, uuid=value, user=user)
91+
except ValidationError:
92+
# we allow for supplement_stack_uuid to also be passed in here, a bit of a hack
93+
validate_model_uuid(SupplementStack, uuid=value, user=user)
94+
8595
return value
8696

8797
def validate(self, validated_data):
98+
"""
99+
This code isn't pretty, but it's because i'm jamming supplement stack and supplements in one view
100+
"""
88101
user = self.context["request"].user
89102
is_creating_instance = not self.instance
90103

91104
if validated_data.get("supplement"):
92-
supplement_uuid = validated_data["supplement"]["uuid"]
93-
supplement = Supplement.objects.get(uuid=supplement_uuid, user=user)
94-
validated_data["supplement"] = supplement
105+
supplement = validated_data.pop("supplement")
106+
supplement_uuid = supplement["uuid"]
107+
108+
try:
109+
supplement = Supplement.objects.get(uuid=supplement_uuid, user=user)
110+
validated_data["supplement"] = supplement
111+
112+
except ObjectDoesNotExist:
113+
# don't allow supplement stacks if it's not a create operation
114+
if not is_creating_instance:
115+
raise
116+
117+
# if it doesn't exist, it's a supplement stack
118+
stack = SupplementStack.objects.get(uuid=supplement_uuid, user=user)
119+
validated_data["stack"] = stack
95120

96-
if is_creating_instance:
121+
if is_creating_instance and validated_data.get("supplement"):
97122
if self.Meta.model.objects.filter(
98-
user=user, supplement=supplement, time=validated_data["time"],
123+
user=user,
124+
supplement=supplement,
125+
time=validated_data["time"],
99126
).exists():
100127
raise ValidationError(
101-
f"Fields user, supplement, and time are not unique!"
128+
"Fields user, supplement, and time are not unique!"
102129
)
130+
elif is_creating_instance and validated_data.get("stack"):
131+
stack = validated_data["stack"]
132+
stack_supplements = [item.supplement for item in stack.compositions.all()]
133+
134+
for supplement in stack_supplements:
135+
if self.Meta.model.objects.filter(
136+
user=user,
137+
supplement=supplement,
138+
time=validated_data["time"],
139+
).exists():
140+
raise ValidationError(
141+
"Fields user, supplement, and time are not unique!"
142+
)
103143

104144
return validated_data
145+
146+
def create(self, validated_data):
147+
if validated_data.get("supplement"):
148+
# normal drf serializers, change nothing
149+
return super().create(validated_data)
150+
151+
elif validated_data.get("stack"):
152+
stack = validated_data.pop("stack")
153+
stack_compositions = stack.compositions.all()
154+
155+
created_instances = []
156+
for composition in stack_compositions:
157+
results = validated_data.copy()
158+
supplement = composition.supplement
159+
160+
# a stack might have a quantity of 2 of something
161+
updated_quantity = results["quantity"] * composition.quantity
162+
163+
results["supplement"] = supplement
164+
results["quantity"] = updated_quantity
165+
166+
created_instance = self.Meta.model.objects.create(**results)
167+
created_instances.append(created_instance)
168+
169+
return created_instances

open/core/betterself/tests/views/test_supplement_log_views.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from open.core.betterself.factories import (
1010
SupplementLogFactory,
1111
SupplementFactory,
12+
SupplementStackFactory,
13+
SupplementStackCompositionFactory,
1214
)
1315
from open.core.betterself.models.supplement_log import SupplementLog
1416
from open.core.betterself.tests.mixins.resource_mixin import (
@@ -148,6 +150,42 @@ def test_display_name_on_log_serializer_some_days_ago(self):
148150
display_name = response.data["display_name"]
149151
self.assertTrue("8.5 days ago" in display_name, display_name)
150152

153+
def test_create_supplement_log_with_supplement_stack(self):
154+
"""
155+
dpy test open.core.betterself.tests.views.test_supplement_log_views.TestSupplementLogViews.test_create_supplement_log_with_supplement_stack --keepdb
156+
"""
157+
# a hidden feature, not really restful, but allow a user to send a supplement_stack_uuid
158+
# to create a set of supplements taken at the same time
159+
160+
supplements = SupplementFactory.create_batch(3, user=self.user_1)
161+
162+
stack = SupplementStackFactory(user=self.user_1)
163+
164+
compositions = []
165+
for supplement in supplements:
166+
composition = SupplementStackCompositionFactory(
167+
user=self.user_1, supplement=supplement, stack=stack, quantity=2
168+
)
169+
compositions.append(composition)
170+
171+
stack_uuid = stack.uuid
172+
173+
utc_now = get_utc_now()
174+
post_data = {
175+
"supplement_uuid": str(stack_uuid),
176+
"time": utc_now.isoformat(),
177+
"quantity": 5,
178+
}
179+
180+
response = self.client_1.post(self.url, data=post_data)
181+
self.assertEqual(response.status_code, 200, response.data)
182+
183+
for supplement in supplements:
184+
matching_log = SupplementLog.objects.get(
185+
supplement=supplement, quantity=10, user=self.user_1, time=utc_now
186+
)
187+
self.assertIsNotNone(matching_log)
188+
151189

152190
class TestSupplementLogGetUpdateDelete(
153191
BetterSelfResourceViewTestCaseMixin, TestCase, GetTestsMixin, DeleteTestsMixin

open/core/betterself/views/supplement_log_views.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import logging
22

3+
from rest_framework.response import Response
4+
35
from open.core.betterself.models.supplement_log import SupplementLog
46
from open.core.betterself.serializers.supplement_log_serializers import (
57
SupplementLogReadSerializer,
@@ -18,6 +20,23 @@ class SupplementLogCreateListView(BaseCreateListView):
1820
read_serializer_class = SupplementLogReadSerializer
1921
create_serializer_class = SupplementLogCreateUpdateSerializer
2022

23+
def post(self, request):
24+
context = {"request": request}
25+
serializer = self.create_serializer_class(data=request.data, context=context)
26+
27+
serializer.is_valid(raise_exception=True)
28+
29+
# normal operation, proceed as normal
30+
if "supplement" in serializer.validated_data:
31+
instance = serializer.save()
32+
serialized_data = self.read_serializer_class(instance).data
33+
else:
34+
# supplement_stack - do some non-elegant stuff
35+
instances = serializer.save()
36+
serialized_data = self.read_serializer_class(instances, many=True).data
37+
38+
return Response(serialized_data)
39+
2140

2241
class SupplementLogGetUpdateView(BaseGetUpdateDeleteView):
2342
model_class = SupplementLog

0 commit comments

Comments
 (0)