Create CommentManager to query for comments that are accessible by a given user

Review Request #12309 — Created May 30, 2022 and submitted

maubin
Review Board
release-5.0.x
12296
reviewboard

Currently there is no efficient way to query for comments that are
accessible by a given user when using <AnyCommentClass>.objects. This change
creates a CommentManager and adds a method such that
<AnyCommentClass>.objects.accessible(user) returns a queryset of comments that
are accessible by the given user.

  • Wrote unit tests for CommentManager and they pass.
Summary Author
Create CommentManager to query for comments that are accessible
Michelle
Description From Last Updated

Most of my comments on the other manager change apply here as well.

chipx86chipx86

This looks great! The only thing I want to see before this ships is some more extensive pieces of test …

chipx86chipx86

F401 'reviewboard.reviews.models.FileAttachmentComment' imported but unused

reviewbotreviewbot

F401 'reviewboard.reviews.models.GeneralComment' imported but unused

reviewbotreviewbot

F401 'reviewboard.reviews.models.ScreenshotComment' imported but unused

reviewbotreviewbot

W292 no newline at end of file

reviewbotreviewbot

This should probably be isinstance(user_or_username, str). It wouldn't make sense to query for username=False. We could add assert isinstance(user_or_username, (User, …

daviddavid

Same issue here.

daviddavid

Rather than abbreviating, let's keep the naming consistent with what we use in the other managers. I know in this …

chipx86chipx86

We can probably get away with just testing one type, since the manager won't be affected by the model type. …

chipx86chipx86

Missing a trailing period.

chipx86chipx86

Okay I made some comments about these lines as general guidance, but I think what's ideal here is to not …

chipx86chipx86

This can be if user.is_anonymous.

chipx86chipx86

Rather than .exclude, we should be able to use .filter and check against True. It's easier to rationalize the logic …

chipx86chipx86

Same comment here. Nicer to work as a filter.

chipx86chipx86

This comment is no longer applicable.

chipx86chipx86

Do we need transform? We should be able to compare the objects directly.

chipx86chipx86
Checks run (1 failed, 1 succeeded)
flake8 failed.
JSHint passed.

flake8

maubin
maubin
maubin
david
  1. 
      
  2. reviewboard/reviews/managers.py (Diff revision 4)
     
     
     

    This should probably be isinstance(user_or_username, str). It wouldn't make sense to query for username=False.

    We could add assert isinstance(user_or_username, (User, AnonymousUser, str)) to handle incorrect callers.

  3. reviewboard/reviews/managers.py (Diff revision 4)
     
     

    Same issue here.

  4. 
      
maubin
chipx86
  1. 
      
  2. Most of my comments on the other manager change apply here as well.

  3. reviewboard/reviews/managers.py (Diff revision 5)
     
     

    Rather than abbreviating, let's keep the naming consistent with what we use in the other managers. I know in this case it's likely to be for line length limits, but you can have the value in Q(field=) wrap to the next line as needed.

  4. reviewboard/reviews/tests/test_comment_manager.py (Diff revision 5)
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    We can probably get away with just testing one type, since the manager won't be affected by the model type.

    If we wanted to ensure we're testing with each comment type, what we'd want to do is create a mixin class that takes the comment model we'd test with, have all unit tests operate on that model, and then have subclasses for each comment type. But it's probably not worth it, given the logic isn't sensitive to the type of model.

    The docstrings can also just be CommentManager instead of worrying about the .objects convention.

  5. 
      
maubin
chipx86
  1. 
      
  2. reviewboard/reviews/managers.py (Diff revision 6)
     
     

    Missing a trailing period.

  3. reviewboard/reviews/managers.py (Diff revision 6)
     
     
     
     
     
     
     

    Okay I made some comments about these lines as general guidance, but I think what's ideal here is to not have two places that are building queryset logic.

    _query() is already considering quite a lot of options for building up the queryset. It's easy to rationalize what's happening when reading that logic, but harder when we then have to mentally combine those built queries with this block. We should aim to have one and only one block of logic building any query involving access controls.

    I'd suggest we figure out what public should be up-front and pass that in above.

    _query() should also be responsible already for the user access (anonymous vs. authed vs. superuser). It looks like it's trying to at least, and that'd be the end goal so that any other wrappers around _query() get the right behavior without duplicating this block.

    1. Ok this makes sense, originally I was having trouble on how to remove unpublished reviews that do not not belong to the user from the queryset. Now I've found a way to move this logic into the _query() method where we perform other ACL logic (see my next review request).

  4. reviewboard/reviews/managers.py (Diff revision 6)
     
     

    This can be if user.is_anonymous.

  5. reviewboard/reviews/managers.py (Diff revision 6)
     
     

    Rather than .exclude, we should be able to use .filter and check against True. It's easier to rationalize the logic if we're not having to inverse.

  6. reviewboard/reviews/managers.py (Diff revision 6)
     
     
     

    Same comment here. Nicer to work as a filter.

  7. This comment is no longer applicable.

  8. Do we need transform? We should be able to compare the objects directly.

    1. You're right, I misread the docs for assertQuerysetEqual and thought that was the transform was needed.

  9. 
      
maubin
maubin
maubin
maubin
chipx86
  1. 
      
  2. This looks great! The only thing I want to see before this ships is some more extensive pieces of test data. When dealing with queries or access checks specifically, we should register objects that should not be queried, in order to ensure we don't see them in results.

    For access-related tests, that means any combination of access controls that should fail should be included. For example, if testing Local Site functionality, we should have objects on the global site and a different Local Site registered, and they shouldn't be in the results.

  3. 
      
maubin
maubin
chipx86
  1. Ship It!
  2. 
      
maubin
Review request changed

Status: Closed (submitted)

Change Summary:

Pushed to release-5.0.x (41fd09b)
Loading...