In Base(1): Review UI URLs, Review UIs are getting the ability to define custom URLs for internal use, like re-rendering content or calculating data for dynamic display.

This task builds upon that by adding a standard _render/ URL for TextBasedReviewUI. This would ultimately take a type= argument specifying (source or rendered), which could be passed by the caller. We may even want to be able to let review UIs handle other types as well, but that's not a requirement for now.

TextBasedReviewUI should provide a view for this URL that does the following:

  1. Check if the calling user has access to the review request and file attachment (so we don't risk any security issues)
  2. Fetch the review request and file attachment
  3. Parse any query arguments and pass them to the correct rendering function (which must be updated to take **kwargs).

Security is important, and we don't want to duplicate effort. So instead of repeating logic, we can have the view make use of ReviewRequestViewMixin (reviewboard/reviews/views.py) to get the correct security and review request lookup logic by default. See how ReviewFileAttachmentView makes use of this.

Now, ReviewFileAttachmentView also has some complex lookups (for file_attachment and file_attachment_diff_id) that we don't want to duplicate, so we should pull some of that into utility methods in a new ReviewFileAttachmentViewMixin. Then, both ReviewFileAttachmentView and our own views can look up file attachments and diffed file attachments in exactly the same way, keeping both simple.

Testing

It'll be important to write unit tests for this. They must cover:

  1. Resolving the new URL.
  2. Making calls to the URL with:
    1. Review requests the user has permission to see
    2. Review requests the user does not have permission to see:
      1. Drafts from another user
      2. Review request belongs to a Local Site the user does not have access to
      3. Review request assigns an invite-only review group the user does not have access to
      4. Review request is on a private repository the user does not have access to
  3. Creating a dummy subclass of TextBasedReviewUI that handles different render options, make calls with those options, compare the results.