4616: serialize_avatar_url_field fails for any user without an avatar

kyz
brennie
brennie

What version are you running?

ReviewBoard 3.0.1, just upgraded from 2.5.14

What's the URL of the page containing the problem?

Several. Reproduction example is /reviews/r/1234

What steps will reproduce the problem?

  1. Go to a new or open review which you can edit
  2. Edit the People box: clear it and start typing something that would match the name of a user who doesn't have an avatar

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

Expected: people's name suggestions
Actual: "HTTP 500 INTERNAL SERVER ERROR" alert appears on screen

What operating system are you using? What browser?

Linux. Firefox

Please provide any additional information below.

I've upgraded an existing ReviewBoard 2.5.x installation to 3.0.1.

I've configured ReviewBoard so that only File Upload avatars are allowed, and they are the default. So far, only one user (me) has uploaded an avatar.

The problem occurs with any API call that gets user data, where that user has not uploaded an avatar.

Examples:

  • /reviews/api/users/?q=stuart succeeds because it only matches me, and I have an avatar
  • /reviews/api/users/?q=sally fails because it only matches someone without an avatar
  • /reviews/api/users/?q=s fails because it only matches more than one person, at least of one whom does not have an avatar
  • /reviews/api/users/?q=q succeeds because it matches nobody

Other API calls seen failing with the same problem:

  • /reviews/users/user.name/infobox/
  • /reviews/api/search/?q=user

The traceback is as follows:

Traceback (most recent call last):

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Django-1.6.11-py2.7.egg/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Django-1.6.11-py2.7.egg/django/views/decorators/cache.py", line 52, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Django-1.6.11-py2.7.egg/django/views/decorators/vary.py", line 19, in inner_func
    response = func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/resources/base.py", line 243, in __call__
    request, method, view, api_format=api_format, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/base.py", line 338, in call_method_view
    request, method, view, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/resources/mixins/api_tokens.py", line 66, in call_method_view
    request, method, view, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/resources/mixins/oauth2_tokens.py", line 102, in call_method_view
    request, method, view, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/resources/base.py", line 314, in call_method_view
    return view(request, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/decorators.py", line 169, in _check
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 319, in _validate
    return view_func(*args, **new_kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/util/decorators.py", line 77, in _call
    func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/resources/user.py", line 224, in get_list
    return super(UserResource, self).get_list(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/decorators.py", line 37, in _check
    return webapi_login_required(view_func)(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 146, in _checklogin
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/decorators.py", line 169, in _check
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 319, in _validate
    return view_func(*args, **new_kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/base.py", line 204, in get_list
    return self._get_list_impl(request, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/base.py", line 219, in _get_list_impl
    return super(WebAPIResource, self).get_list(request, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/util/decorators.py", line 75, in _call
    f = augmented_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 125, in _call
    return view_func(*args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/decorators.py", line 319, in _validate
    return view_func(*args, **new_kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/resources/base.py", line 611, in get_list
    **self.build_response_args(request))

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/responses.py", line 164, in __init__
    for obj in self.results

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/resources/base.py", line 609, in <lambda>
    obj, request=request, *args, **kwargs),

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/resources/user.py", line 129, in serialize_object
    obj, request=request, *args, **kwargs)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/Djblets-1.0.1-py2.7.egg/djblets/webapi/resources/base.py", line 843, in serialize_object
    value = serialize_func(obj, request=request)

  File "/opt/rh/python27/root/usr/lib/python2.7/site-packages/ReviewBoard-3.0.1-py2.7.egg/reviewboard/webapi/resources/user.py", line 154, in serialize_avatar_url_field
    return service.get_avatar_urls(request, user, 48)['1x']

KeyError: u'1x'
#1 kyz

The following change fixes the issue:

--- ./reviewboard/webapi/resources/user.py.orig 2017-12-12 13:31:26.625704990 +0000
+++ ./reviewboard/webapi/resources/user.py  2017-12-12 13:32:38.055878344 +0000
@@ -151,7 +151,7 @@
             service = avatar_services.for_user(user)

             if service:
-                return service.get_avatar_urls(request, user, 48)['1x']
+                return service.get_avatar_urls(request, user, 48).get('1x')

         return None
chipx86
#2 chipx86
  • -New
    +Confirmed
  • -Priority:Medium
    +Component:API
    +Component:Avatars
    +Component:Avatars
    +Priority:High
  • +brennie
chipx86
#3 chipx86
  • +Release-3.0.x
brennie
#5 brennie

This has been pushed to release-3.0.x as f50e598 and has been fixed in Review Board 3.0.3.