WIP: User Feedback for PickUps Tests #342
Conversation
…t out in serializers.py as well as some flake8 corrections
…into feedback3
…ot a member of group
Codecov Report
@@ Coverage Diff @@
## master #342 +/- ##
==========================================
+ Coverage 98.28% 98.34% +0.06%
==========================================
Files 155 162 +7
Lines 4202 4358 +156
Branches 178 180 +2
==========================================
+ Hits 4130 4286 +156
Misses 52 52
Partials 20 20
Continue to review full report at Codecov.
|
I can't wait for the next test which is hopefully (Sorry, I first wrote |
…method GET (one fails at the moment)
…e user is non-member of group, see comments
…omments in apy.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope my feedback helps you!
foodsaving/stores/api.py
Outdated
# serializer_class=FeedbackSerializer | ||
# ) | ||
|
||
# returns 1 failure in tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have two types of operations to consider when limiting access: retrievals (GET) and modifications (POST).
- For retrievals, you can filter with the
queryset
. I did this there for example.
This would be the code I'd try here:
queryset = FeedbackModel.objects # make all feedback objects available by default
def get_queryset(self):
# apply additional filters depending on the user who makes the request
return self.queryset.filter(about__store__group__members=self.request.user)
- For modifications, you most likely need to validate the values given in the request body. This should be done in the serializer.
(This way, I think you can get rid of your detail()
, get_permissions()
and get_serializer_class()
methods.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, this is definately helpful! 👍
foodsaving/stores/serializers.py
Outdated
|
||
""" | ||
Tilmann suggested to make 'given_by' read_only - but the following code produces errors | ||
extra_kwargs = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be interested to see what errors you get. Probably the database complains that the given_by
field is missing a value, as it is non-nullable.
To solve this issue, you need to provide the given_by
field when creating the entry. Override the create()
method for that.
def create(self, validated_data):
validated_data['given_by'] = self.context['request'].user
return super().create(validated_data)
I just noticed that you discovered the new read_only_fields
shortcut. Great, please use that instead of extra_kwargs
!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we are getting errors also for read_only_fields
. We will try it then with create()
to avoid errors.
""" | ||
self.client.force_login(user=self.user) | ||
response = self.client.get(self.url) | ||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND, response.data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect an empty list instead of 404
, similar to here
Explanation: the request goes to /api/feedback/
, which is not group-specific. It will return the list of all feedback the user has access to, which is an empty list in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have done that yesterday evening. You can look it up in our follow-up commit that I pushed.
…, group member and collector
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks very good! I added some minor suggestions.
config/urls.py
Outdated
@@ -53,6 +53,9 @@ | |||
router.register('invitations', InvitationsViewSet) | |||
router.register('invitations', InvitationAcceptViewSet) | |||
|
|||
# Feedback endpoints | |||
router.register(r'feedback', FeedbackViewSet, base_name='user_feedback') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the base_name
good for? Maybe it can be removed.
foodsaving/stores/api.py
Outdated
from foodsaving.utils.mixins import PartialUpdateModelMixin | ||
|
||
pre_pickup_delete = Signal() | ||
pre_series_delete = Signal() | ||
post_store_delete = Signal() | ||
post_feedback_delete = Signal() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems not needed.
foodsaving/stores/models.py
Outdated
@@ -30,6 +30,13 @@ def __str__(self): | |||
return '{} ({})'.format(self.name, self.group) | |||
|
|||
|
|||
class Feedback(BaseModel): | |||
given_by = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='user_feedback') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe change the related name to feedback
, then it can be accessed from an user instance like this user.feedback
instead of user.user_feedback
.
foodsaving/stores/serializers.py
Outdated
pickup_date = about # PickupDateModel.objects.get(pk=about) | ||
group = pickup_date.store.group | ||
# is the member assiged to the pickup? | ||
if user not in group.members.all(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will merge a pull request today #360 that allows you to use group.is_member(user)
to reduce code duplication.
foodsaving/stores/serializers.py
Outdated
if user not in group.members.all(): | ||
raise serializers.ValidationError(_('You are not member of the store\'s group.')) | ||
# if user is in self.context['request']. | ||
if about not in self.context['request'].user.pickup_dates.all(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, #360 also introduces about.is_collector(user)
. Looks a bit easier to understand then :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, we know now what is needed to refactor. Thank you.
foodsaving/stores/models.py
Outdated
@@ -30,6 +30,13 @@ def __str__(self): | |||
return '{} ({})'.format(self.name, self.group) | |||
|
|||
|
|||
class Feedback(BaseModel): | |||
given_by = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='user_feedback') | |||
about = models.ForeignKey('PickupDate') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the name about
unintuitive, and it sounds like it's maybe a generic relation (but it's not) - how about pickup
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with both, change it if you agree with Nick and you feel like doing refactoring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we thought the same. about
is too unintuitive. we will change it then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And are you sure that the name pickup
will not crash with pickup
at different places in code?
foodsaving/stores/serializers.py
Outdated
|
||
# if not self.context['request'].user.groups.filter(id=group_id).exists(): | ||
# raise serializers.ValidationError(_('You are not member of the store\'s group.')) | ||
# return user_id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented out code
foodsaving/stores/api.py
Outdated
# if self.action == 'retrieve': | ||
# self.permission_classes = (IsAuthenticated, IsMember,) | ||
|
||
# return super().get_permissions() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented out code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎇
We do a new WIP Pull request because we had to remove our GitHub branch feedback3 due to local merge conflict. But we saw the suggestions and we integrated them into our code.
Tiltec: we added 2 tests in stores/tests/test_feedback_api and they both work. There are 2 things we did not finish today: 1. pull last changes from master (we have a merge conflict there) 2. integrate read_only for given_by in serializers.py.