Skip to content
This repository has been archived by the owner on May 20, 2024. It is now read-only.

WIP: User Feedback for PickUps Tests #342

Merged
merged 55 commits into from Aug 31, 2017
Merged

WIP: User Feedback for PickUps Tests #342

merged 55 commits into from Aug 31, 2017

Conversation

mddemarie
Copy link
Contributor

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.

@codecov-io
Copy link

codecov-io commented Aug 10, 2017

Codecov Report

Merging #342 into master will increase coverage by 0.06%.
The diff coverage is 100%.

Impacted file tree graph

@@            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
Impacted Files Coverage Δ
foodsaving/stores/models.py 96.49% <100%> (+0.16%) ⬆️
...aving/stores/migrations/0020_auto_20170831_1312.py 100% <100%> (ø)
foodsaving/stores/tests/test_feedback_api.py 100% <100%> (ø)
...aving/stores/migrations/0018_auto_20170831_1256.py 100% <100%> (ø)
...aving/stores/migrations/0019_auto_20170831_1306.py 100% <100%> (ø)
...aving/stores/migrations/0021_auto_20170831_1341.py 100% <100%> (ø)
foodsaving/stores/tests/test_models.py 100% <100%> (ø) ⬆️
foodsaving/stores/api.py 100% <100%> (ø) ⬆️
foodsaving/stores/migrations/0016_feedback.py 100% <100%> (ø)
foodsaving/stores/serializers.py 97.94% <100%> (+0.21%) ⬆️
... and 8 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4569c0b...de676d4. Read the comment docs.

@tiltec
Copy link
Member

tiltec commented Aug 10, 2017

I can't wait for the next test which is hopefully test_create_feedback_as_member and it shows how a feedback gets created 🍾 🎉 :)

(Sorry, I first wrote user instead of member)

Copy link
Member

@tiltec tiltec left a 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!

# serializer_class=FeedbackSerializer
# )

# returns 1 failure in tests
Copy link
Member

@tiltec tiltec Aug 24, 2017

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).

  1. 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)
  1. 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.)

Copy link
Contributor Author

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! 👍


"""
Tilmann suggested to make 'given_by' read_only - but the following code produces errors
extra_kwargs = {
Copy link
Member

@tiltec tiltec Aug 24, 2017

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!

Copy link
Contributor Author

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)
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

@tiltec tiltec left a 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')
Copy link
Member

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.

from foodsaving.utils.mixins import PartialUpdateModelMixin

pre_pickup_delete = Signal()
pre_series_delete = Signal()
post_store_delete = Signal()
post_feedback_delete = Signal()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems not needed.

@@ -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')
Copy link
Member

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.

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():
Copy link
Member

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.

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():
Copy link
Member

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 :)

Copy link
Contributor Author

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.

@@ -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')
Copy link
Member

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?

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?


# 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code

# if self.action == 'retrieve':
# self.permission_classes = (IsAuthenticated, IsMember,)

# return super().get_permissions()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code

Copy link
Member

@tiltec tiltec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎇

@tiltec tiltec merged commit 149981f into master Aug 31, 2017
@tiltec tiltec deleted the feedback3 branch August 31, 2017 16:12
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
6 participants