4635: AvatarService requires get_avatar_urls_uncached

Misery

What version of Djblets are you using?

1.0.2 (RB 3.0.2)

Which module(s) have the problem?

AvatarService

What steps will reproduce the problem?

  1. Enable my CustomAvatarService (https://github.com/misery/CustomUrlAvatar)
  2. Go to http://localhost/admin/db/reviews/defaultreviewer/1/
  3. RB throws error 500

What is the expected output? What do you see instead?

Expected:
Show the site or let reviewboard print missing REQUIRED methods immediately instead of "stacktrace on random sites".

https://www.reviewboard.org/docs/djblets/1.0/coderef/python/djblets.avatars.services.base/

A service that provides avatar support.

At the very least, subclasses must set the avatar_service_id and name attributes, as well as override the get_avatar_urls() method.

"get_avatar_urls_uncached" should be mentioned if required.

What version of Python and Django?

python 2.7.14
django 1.6.11.6

Please provide any additional information below.

Traceback (most recent call last):

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/core/handlers/base.py", line 137, in get_response
response = response.render()

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/response.py", line 82, in rendered_content
content = template.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 140, in render
return self._render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
return self.nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/loader_tags.py", line 123, in render
return compiled_parent._render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
return self.nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/loader_tags.py", line 123, in render
return compiled_parent._render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
return self.nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/defaulttags.py", line 203, in render
nodelist.append(node.render(context))

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/loader_tags.py", line 155, in render
return self.render_template(self.template, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/loader_tags.py", line 137, in render_template
output = template.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 140, in render
return self._render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
return self.nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/defaulttags.py", line 203, in render
nodelist.append(node.render(context))

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/defaulttags.py", line 203, in render
nodelist.append(node.render(context))

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/defaulttags.py", line 305, in render
return nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/defaulttags.py", line 305, in render
return nodelist.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 840, in render
bit = self.render_node(node, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 854, in render_node
return node.render(context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 897, in render
return render_value_in_context(output, context)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/template/base.py", line 875, in render_value_in_context
value = force_text(value)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/utils/encoding.py", line 100, in force_text
s = s.unicode()

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/forms/forms.py", line 425, in str
return self.as_widget()

File "/opt/reviewboard/dist/lib/python2.7/site-packages/django/forms/forms.py", line 475, in as_widget
return widget.render(name, self.value(), attrs=attrs)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/reviewboard/admin/form_widgets.py", line 101, in render
.get_avatar_urls_uncached(user, 40)

File "/opt/reviewboard/dist/lib/python2.7/site-packages/djblets/avatars/services/base.py", line 174, in get_avatar_urls_uncached
% type(self)

NotImplementedError: <class 'custom_url_avatar.extension.CustomAvatarService'> must implement get_avatar_urls_uncached().

chipx86
#1 chipx86
  • -New
    +Confirmed
  • +reviewboard:Release-3.0.x
  • -Project:RBTools
    +EasyFix
    +Project:ReviewBoard
#2 floriecai

I'll take this one.

chipx86
#3 chipx86

This would be a good one to fix in the same change: https://hellosplat.com/s/beanbag/tickets/4634/

Misery
#4 Misery

Thanks!

By the way.... get_avatar_urls provides the request and get_avatar_urls_uncached provides user and size only.
As I need to check whether the user uses HTTP or HTTPS I cannot provide a correct url with my extension. Otherwise the user could have a "mixed content" problem "https -> http" or a broken link "no https". Also maybe I don't know the used host.

Any idea how I can fix this in an extension?

Snippet:

        '1x': mark_safe(
            self._extension.settings[CONFIG_CUSTOM_URL].format(
           scheme='https' if request.is_secure() else 'http',
           host=request.get_host(),
           user=user,
           size=size,
         ))
chipx86
#5 chipx86

If you use //www.blah.com, it will select the same HTTP/HTTPS scheme as the current page.

That said, I agree that uncached should ideally have the request, but the etag building would have to take care to provide the relevant data in the etag.

david
#6 david

Fixed in djblets release-1.0.x (52a4d41). This will shp in 1.0.10. Thanks!

  • -Confirmed
    +Fixed