Review UIs today are served up at the /r/<id>/file/<id>/ URL (or /r/<id>/file/<id>-<id>/ for diffing). They're currently unable to set up any other URLs for utility purposes (such as re-rendering any text content).

This task involves adding the ability for a ReviewUI subclass to provide URLs they want to make available. These URLs would be relative to the main URLs listed above. For instance, an internal text rendering URL could be registered as a relative _rendered/ URL.

Now, that seems like it'd be trivial, but there are a few things to keep in mind:

  1. Because Review UIs are pluggable (extensions can provide new ones), we can't know each possible URL up-front for the [urls.py](<http://urls.py>) files.
  2. Django doesn't natively support dynamically-constructed URLs, meaning that they'd normally need to be registered up-front.
  3. We'd have to consider what happens if multiple review UIs want to register the same URL entries. We don't want them to conflict.

Dynamic URLs

Fortunately, we've solved #2 with our DynamicURLResolver. This is a class that can be instantiated and then added into a [urls.py](<http://urls.py>) file. New URLs can then be dynamically added to it or removed from it.

You can see how this works by looking at hostingsvcs/urls.py and searching for dynamic_urls in hostingsvcs/service.py.

We would construct one of these in reviewboard/reviews/urls.py, called dynamic_review_ui_urls. Then, in the # File attachments part of that file, you'd update it to look like:

url('^file/(?P<file_attachment_id>\\d+)/', include([
    url('$', views.ReviewFileAttachemntView.as_view(),
        name='file-attachment'),
    dynamic_review_ui_urls,
]),

# And same for the diff version

Namespacing

For #3, we have to namespace these URLs. That means that an example URL of _rendered/ would have to go into a namespace specific to the containing review UI. For instance, /r/<id>/file/<id>/json/_rendered/. That would keep it from conflicting with an XML one, which would live in /r/<id>/file/<id>/xml/_rendered/, or a plain text one at /r/<id>/file/<id>/text/_rendered/.