def test_persona_sha512_base64_maybe_not_latin1(self): passwd = u'fo\xf3' hsh = hashlib.sha512(self.bytes_ + passwd.encode('latin1')).hexdigest() u = UserProfile(password='******' % (encodestring(self.bytes_), hsh)) assert u.check_password(self.utf) is False assert u.has_usable_password() is True
def test_persona_sha512_md5_base64(self): md5 = hashlib.md5('password').hexdigest() hsh = hashlib.sha512(self.bytes_ + md5).hexdigest() u = UserProfile(password='******' % (encodestring(self.bytes_), hsh)) assert u.check_password('password') is True assert u.has_usable_password() is True
def test_users_list_truncate_display_name(): u = UserProfile(username='******', display_name='Some Very Long Display Name', pk=1) truncated_list = users_list([u], None, 10) assert truncated_list == ( u'<a href="%s" title="%s">Some Very...</a>' % (u.get_url_path(), u.name))
def test_user_link(): u = UserProfile(username='******', display_name='John Connor', pk=1) assert user_link(u) == ( '<a href="%s" title="%s">John Connor</a>' % (u.get_url_path(), u.name)) # handle None gracefully assert user_link(None) == ''
def test_valid_old_password(self): hsh = hashlib.md5(encoding.smart_str(self.utf)).hexdigest() u = UserProfile(password=hsh) assert u.check_password(self.utf) is True # Make sure we updated the old password. algo, salt, hsh = u.password.split('$') eq_(algo, 'sha512') eq_(hsh, get_hexdigest(algo, salt, self.utf)) assert u.has_usable_password() is True
def test_valid_old_password(self): hsh = hashlib.md5(force_bytes(self.utf)).hexdigest() u = UserProfile(password=hsh) assert u.check_password(self.utf) is True # Make sure we updated the old password. algo, salt, hsh = u.password.split('$') assert algo == 'sha512' assert hsh == get_hexdigest(algo, salt, self.utf) assert u.has_usable_password() is True
def test_authors_few(self): row = Mock() row.authors = [(123, 'bob'), (456, 'steve')] doc = pq(self.table.render_authors(row)) assert doc('span').text() == 'bob steve' assert doc('span a:eq(0)').attr('href') == UserProfile.create_user_url( 123, username='******') assert doc('span a:eq(1)').attr('href') == UserProfile.create_user_url( 456, username='******') assert doc('span').attr('title') == 'bob steve'
def test_user_link_unicode(): """make sure helper won't choke on unicode input""" u = UserProfile(username=u'jmüller', display_name=u'Jürgen Müller', pk=1) assert user_link(u) == ( u'<a href="%s" title="%s">Jürgen Müller</a>' % ( u.get_url_path(), u.name)) u = UserProfile(username='******', pk=1) assert user_link(u) == ( u'<a href="%s" title="%s">%s</a>' % (u.get_url_path(), u.name, u.username))
def test_user_link_xss(): u = UserProfile(username='******', display_name='<script>alert(1)</script>', pk=1) html = "<script>alert(1)</script>" assert user_link(u) == '<a href="%s" title="%s">%s</a>' % ( u.get_url_path(), html, html) u = UserProfile(username='******', display_name="""xss"'><iframe onload=alert(3)>""", pk=1) html = """xss"'><iframe onload=alert(3)>""" assert user_link(u) == '<a href="%s" title="%s">%s</a>' % ( u.get_url_path(), html, html)
def test_user_log_as_argument(self): """ Tests that a user that has something done to them gets into the user log. """ u = UserProfile(username='******') u.save() amo.log(amo.LOG['ADD_USER_WITH_ROLE'], u, 'developer', Addon.objects.get()) entries = ActivityLog.objects.for_user(self.request.user) eq_(len(entries), 1) entries = ActivityLog.objects.for_user(u) eq_(len(entries), 1)
def test_user_log_as_argument(self): """ Tests that a user that has something done to them gets into the user log. """ user = UserProfile(username='******') user.save() ActivityLog.create(amo.LOG.ADD_USER_WITH_ROLE, user, 'developer', Addon.objects.get()) entries = ActivityLog.objects.for_user(self.request.user) assert len(entries) == 1 entries = ActivityLog.objects.for_user(user) assert len(entries) == 1
def test_authors_four(self): row = Mock() row.authors = [(123, 'bob'), (456, 'steve'), (789, 'cvan'), (999, 'basta')] doc = pq(self.table.render_authors(row)) assert doc.text() == 'bob steve cvan ...' assert doc('span a:eq(0)').attr('href') == UserProfile.create_user_url( 123, username='******') assert doc('span a:eq(1)').attr('href') == UserProfile.create_user_url( 456, username='******') assert doc('span a:eq(2)').attr('href') == UserProfile.create_user_url( 789, username='******') assert doc('span').attr('title') == 'bob steve cvan basta', doc.html()
def test_ban_and_disable_related_content_bulk(self, hide_disabled_mock): user_sole = user_factory(email='*****@*****.**', fxa_id='13579') addon_sole = addon_factory(users=[user_sole]) self.setup_user_to_be_have_content_disabled(user_sole) user_multi = user_factory(email='*****@*****.**', fxa_id='24680') innocent_user = user_factory() addon_multi = addon_factory( users=UserProfile.objects.filter( id__in=[user_multi.id, innocent_user.id])) self.setup_user_to_be_have_content_disabled(user_multi) # Now that everything is set up, disable/delete related content. UserProfile.ban_and_disable_related_content_bulk( [user_sole, user_multi]) addon_sole.reload() addon_multi.reload() # if sole dev should have been disabled, but the author retained assert addon_sole.status == amo.STATUS_DISABLED assert list(addon_sole.authors.all()) == [user_sole] # shouldn't have been disabled as it has another author assert addon_multi.status != amo.STATUS_DISABLED assert list(addon_multi.authors.all()) == [innocent_user] # the File objects have been disabled assert not File.objects.filter(version__addon=addon_sole).exclude( status=amo.STATUS_DISABLED).exists() # But not for the Add-on that wasn't disabled assert File.objects.filter(version__addon=addon_multi).exclude( status=amo.STATUS_DISABLED).exists() assert not user_sole._ratings_all.exists() # Even replies. assert not user_sole.collections.exists() assert not user_multi._ratings_all.exists() # Even replies. assert not user_multi.collections.exists() assert not storage.exists(user_sole.picture_path) assert not storage.exists(user_sole.picture_path_original) assert not storage.exists(user_multi.picture_path) assert not storage.exists(user_multi.picture_path_original) assert user_sole.deleted assert user_sole.email == '*****@*****.**' assert user_sole.auth_id assert user_sole.fxa_id == '13579' assert user_multi.deleted assert user_multi.email == '*****@*****.**' assert user_multi.auth_id assert user_multi.fxa_id == '24680' hide_disabled_mock.assert_not_called()
def setUp(self): self.fxa_identify = self.patch( 'olympia.accounts.views.verify.fxa_identify') self.find_user = self.patch('olympia.accounts.views.find_user') self.render_error = self.patch('olympia.accounts.views.render_error') self.request = mock.MagicMock() self.user = AnonymousUser() self.request.user = self.user self.request.session = {'fxa_state': 'some-blob'}
def test_logged_in_disallows_login(self): self.request.data = {'code': 'woah', 'state': 'some-blob'} self.user = UserProfile() self.request.user = self.user assert self.user.is_authenticated() self.fn(self.request) self.render_error.assert_called_with( self.request, views.ERROR_AUTHENTICATED, next_path=None, format='json') assert not self.find_user.called
def render_authors(self, record): authors = record.authors if not len(authors): return '' more = ' '.join( safe_substitute(u'%s', uname) for (_, uname) in authors) author_links = ' '.join( safe_substitute(u'<a href="%s">%s</a>', UserProfile.create_user_url(id_), uname) for (id_, uname) in authors[0:3]) return u'<span title="%s">%s%s</span>' % ( more, author_links, ' ...' if len(authors) > 3 else '')
def test_error_no_code_with_safe_path_logged_in(self): request = self.make_request() request.user = UserProfile() assert len(get_messages(request)) == 0 response = self.render_error( request, views.ERROR_NO_CODE, next_path='/over/here') assert response.status_code == 302 messages = get_messages(request) assert len(messages) == 1 assert 'could not be parsed' in next(iter(messages)).message assert_url_equal( response['location'], self.migrate_url(to='/over/here'))
def test_fxa_config_logged_in(): request = RequestFactory().get('/en-US/firefox/addons') request.session = {'fxa_state': 'thestate!'} request.user = UserProfile(email='*****@*****.**') assert utils.fxa_config(request) == { 'clientId': 'foo', 'state': 'thestate!', 'email': '*****@*****.**', 'oauthHost': 'https://oauth-stable.dev.lcip.org/v1', 'contentHost': 'https://stable.dev.lcip.org', 'profileHost': 'https://stable.dev.lcip.org/profile/v1', 'scope': 'profile openid', }
def render_authors(self, record): authors = record.authors if not len(authors): return '' more = '\n'.join( safe_substitute(u'%s', uname) for (_, uname) in authors) author_links = ''.join( safe_substitute(u'<a href="%s">%s</a>', UserProfile.create_user_url(id_, username=uname), uname) for (id_, uname) in authors[0:3]) return u'<span title="%s">%s%s</span>' % ( more, author_links, '...' if len(authors) > 3 else '')
def test_allowed_keyerror(self): responses.add( responses.GET, self.expected_url, content_type='application/json', json={'no_reputation_oh_noes': 'garbage'}) request = RequestFactory(REMOTE_ADDR='192.168.0.1').get('/') request.user = UserProfile(email='*****@*****.**') assert self.restriction_class.allow_request(request) assert len(responses.calls) == 1 http_call = responses.calls[0].request assert http_call.headers['Authorization'] == 'APIKey fancy_token' assert http_call.url == self.expected_url
def test_register_success(self): identity = {u'email': u'*****@*****.**', u'uid': u'e0b6f'} user = UserProfile(username='******', email=identity['email']) self.register_user.return_value = user self.fxa_identify.return_value = identity response = self.client.post( self.url, {'code': 'codes!!', 'state': 'some-blob'}) assert response.status_code == 200 assert response.data['email'] == '*****@*****.**' assert (response.cookies['jwt_api_auth_token'].value == response.data['token']) self.fxa_identify.assert_called_with('codes!!', config=FXA_CONFIG) self.register_user.assert_called_with(mock.ANY, identity)
def test_logged_in_disallows_login(self): self.request.data = { 'code': 'foo', 'state': 'some-blob:{}'.format(base64.urlsafe_b64encode('/next')), } self.user = UserProfile() self.request.user = self.user assert self.user.is_authenticated() self.fn(self.request) self.render_error.assert_called_with( self.request, views.ERROR_AUTHENTICATED, next_path='/next', format='json') assert not self.find_user.called
def test_already_logged_in_add_api_token_cookie_if_missing(self): self.request.data = { 'code': 'foo', 'state': 'some-blob:{}'.format(base64.urlsafe_b64encode('/next')), } self.user = UserProfile() self.request.user = self.user assert self.user.is_authenticated() self.request.COOKIES = {} self.fn(self.request) self.render_error.assert_called_with(self.request, views.ERROR_AUTHENTICATED, next_path='/next', format='json') assert not self.find_user.called response = self.render_error.return_value assert response.set_cookie.call_count == 1 response.set_cookie.assert_called_with( views.API_TOKEN_COOKIE, 'fake-api-token', max_age=settings.SESSION_COOKIE_AGE, secure=settings.SESSION_COOKIE_SECURE, httponly=settings.SESSION_COOKIE_HTTPONLY)
def test_blocked_reputation_threshold_email_variant(self): responses.add(responses.GET, self.expected_url, content_type='application/json', json={'reputation': 45}) request = RequestFactory(REMOTE_ADDR='192.168.0.1').get('/') request.user = UserProfile(email='*****@*****.**') # Still blocked as if it was [email protected] assert not self.restriction_class.allow_request(request) assert len(responses.calls) == 1 http_call = responses.calls[0].request assert http_call.headers['Authorization'] == 'APIKey fancy_token' assert http_call.url == self.expected_url
def setUp(self): patcher = mock.patch('olympia.accounts.views.verify.fxa_identify') self.fxa_identify = patcher.start() self.addCleanup(patcher.stop) patcher = mock.patch('olympia.accounts.views.find_user') self.find_user = patcher.start() self.addCleanup(patcher.stop) patcher = mock.patch('olympia.accounts.views.render_error') self.render_error = patcher.start() self.addCleanup(patcher.stop) self.request = mock.MagicMock() self.user = UserProfile() self.request.user = self.user self.request.session = {'fxa_state': 'some-blob'}
def test_empty_password(self): profile = UserProfile(password=None) assert profile.has_usable_password() is False assert not check_password(None, profile.password) assert not profile.check_password(None) profile = UserProfile(password='') assert profile.has_usable_password() is False assert not check_password('', profile.password) assert not profile.check_password('')
def test_user_link_unicode(): """make sure helper won't choke on unicode input""" u = UserProfile(username=u'jmüller', display_name=u'Jürgen Müller', pk=1) assert user_link(u) == (u'<a href="%s" title="%s">Jürgen Müller</a>' % (u.get_url_path(), u.name)) u = UserProfile(username='******', pk=1) assert user_link(u) == (u'<a href="%s" title="%s">%s</a>' % (u.get_url_path(), u.name, u.username))
def test_send_confirmation_email(self): token = 'abcdefghijklmnopqrst' confirmation = APIKeyConfirmation() confirmation.token = token confirmation.user = UserProfile(email='*****@*****.**', display_name='Fô') assert len(mail.outbox) == 0 confirmation.send_confirmation_email() assert len(mail.outbox) == 1 message = mail.outbox[0] expected_url = ( f'http://testserver/en-US/developers/addon/api/key/?token={token}') assert message.to == ['*****@*****.**'] assert message.from_email == 'Mozilla Add-ons <*****@*****.**>' assert message.subject == 'Confirmation for developer API keys' assert expected_url in message.body
def _test_throttling_verb_ip_sustained(self, verb, url, expected_status=201): with freeze_time('2019-04-08 15:16:23.42') as frozen_time: for x in range(0, 50): # Make the user different every time so that we test the ip # throttling. self._add_fake_throttling_action( view_class=self.view_class, url=url, user=UserProfile(pk=42 + x), remote_addr='63.245.208.194', ) # At this point we should be throttled since we're using the same # IP. (we're still inside the frozen time context). response = self.request( verb, url=url, addon='@create-webextension', version='1.0', extra_kwargs={'REMOTE_ADDR': '63.245.208.194'}) assert response.status_code == 429 # One minute later, past the 'burst' throttling period, we're still # blocked by the 'sustained' limit. frozen_time.tick(delta=timedelta(seconds=61)) response = self.request( verb, url=url, addon='@create-webextension', version='1.0', extra_kwargs={'REMOTE_ADDR': '63.245.208.194'}) assert response.status_code == 429 # 'Sustained' throttling is 1 hour, so 3601 seconds later we should # be allowed again. frozen_time.tick(delta=timedelta(seconds=3601)) response = self.request( verb, url=url, addon='@create-webextension', version='1.0', extra_kwargs={'REMOTE_ADDR': '63.245.208.194'}) assert response.status_code == expected_status
def test_user_link_xss(): user = UserProfile(username='******', display_name='<script>alert(1)</script>', pk=1) html = "<script>alert(1)</script>" assert user_link(user) == '<a href="%s" title="%s">%s</a>' % ( user.get_absolute_url(), html, html) user = UserProfile(username='******', display_name="""xss"'><iframe onload=alert(3)>""", pk=1) html = """xss"'><iframe onload=alert(3)>""" assert user_link(user) == '<a href="%s" title="%s">%s</a>' % ( user.get_absolute_url(), html, html)
def test_register_redirects_edit(self): user_qs = UserProfile.objects.filter(email='*****@*****.**') assert not user_qs.exists() identity = {u'email': u'*****@*****.**', u'uid': u'e0b6f'} self.fxa_identify.return_value = identity user = UserProfile(username='******', email='*****@*****.**') self.register_user.return_value = user response = self.client.get(self.url, { 'code': 'codes!!', 'state': ':'.join( [self.fxa_state, base64.urlsafe_b64encode('/go/here')]), }) # This 302s because the user isn't logged in due to mocking. self.assertRedirects( response, reverse('users.edit'), target_status_code=302) self.fxa_identify.assert_called_with('codes!!', config=FXA_CONFIG) assert not self.login_user.called self.register_user.assert_called_with(mock.ANY, identity)
def test_has_read_developer_agreement(self): now = self.days_ago(0) recently = self.days_ago(1) older_date = self.days_ago(42) assert not UserProfile().has_read_developer_agreement() assert not UserProfile( read_dev_agreement=None).has_read_developer_agreement() assert UserProfile( read_dev_agreement=older_date).has_read_developer_agreement() with override_switch('post-review', active=True): Switch.objects.filter(name='post-review').update(modified=recently) # Still False. assert not UserProfile().has_read_developer_agreement() # User has read the agreement, before it was modified for # post-review: it should return False. assert not UserProfile( read_dev_agreement=older_date).has_read_developer_agreement() # User has read the agreement after it was modified for # post-review: it should return True. assert UserProfile( read_dev_agreement=now).has_read_developer_agreement() with override_switch('post-review', active=False): Switch.objects.filter(name='post-review').update(modified=recently) # Still False. assert not UserProfile().has_read_developer_agreement() # Both should be True, the date does not matter any more. assert UserProfile( read_dev_agreement=older_date).has_read_developer_agreement() assert UserProfile( read_dev_agreement=now).has_read_developer_agreement()
def test_user_link_xss(): u = UserProfile(username='******', display_name='<script>alert(1)</script>', pk=1) html = "<script>alert(1)</script>" eq_(user_link(u), '<a href="%s" title="%s">%s</a>' % (u.get_url_path(), html, html)) u = UserProfile(username='******', display_name="""xss"'><iframe onload=alert(3)>""", pk=1) html = """xss"'><iframe onload=alert(3)>""" eq_(user_link(u), '<a href="%s" title="%s">%s</a>' % (u.get_url_path(), html, html))
def test_sharing_box(self): request = Mock() request.user = UserProfile() request.APP = amo.FIREFOX ctx = { 'request': request, 'APP': request.APP, 'LANG': translation.get_language() } doc = pq(sharing_box(ctx)) assert doc.html() assert doc('li').length == len(sharing.SERVICES_LIST) # Make sure services are in the right order. for i in range(len(sharing.SERVICES_LIST)): expected = sharing.SERVICES_LIST[i].shortname assert doc('li').eq(i).attr('class') == expected assert doc('li a').eq(i).attr('target') in ('_blank', '_self'), ( 'Sharing link target must either be blank or self.')
def test_barometer(self): self.client.get('/') collection = Collection(upvotes=1, slug='mccrackin', author=UserProfile(username='******')) # Mock logged out. c = { 'request': Mock(path='yermom', GET=Mock(urlencode=lambda: ''), session={'fxa_state': 'foobar'}), 'user': Mock(), 'settings': Mock() } c['request'].user.is_authenticated.return_value = False doc = pq(barometer(c, collection)) assert doc('form')[0].action == 'https://login' # Mock logged in. c['request'].user.votes.filter.return_value = [Mock(vote=1)] c['request'].user.is_authenticated.return_value = True barometer(c, collection) doc = pq(barometer(c, collection)) assert doc('form')[0].action == ( reverse('collections.vote', args=['clouserw', 'mccrackin', 'up']))
def _test_throttling_verb_ip_burst(self, verb, url, expected_status=201): # Bulk-create a bunch of users we'll need to make sure the user is # different every time, so that we test IP throttling specifically. users = [ UserProfile(username='******' % i, email='*****@*****.**' % i) for i in range(0, 6) ] UserProfile.objects.bulk_create(users) users = UserProfile.objects.filter(email__startswith='bulk') with freeze_time('2019-04-08 15:16:23.42') as frozen_time: for user in users: self._add_fake_throttling_action( view_class=self.view_class, url=url, user=user, remote_addr='63.245.208.194', ) # At this point we should be throttled since we're using the same # IP. (we're still inside the frozen time context). response = self.request( verb, url=url, addon='@create-webextension', version='1.0', extra_kwargs={'REMOTE_ADDR': '63.245.208.194'}) assert response.status_code == 429, response.content # 'Burst' throttling is 1 minute, so 61 seconds later we should be # allowed again. frozen_time.tick(delta=timedelta(seconds=61)) response = self.request( verb, url=url, addon='@create-webextension', version='1.0', extra_kwargs={'REMOTE_ADDR': '63.245.208.194'}) assert response.status_code == expected_status
def test_barometer(self): self.client.get('/') jingo.load_helpers() collection = Collection(upvotes=1, slug='mccrackin', author=UserProfile(username='******')) # Mock logged out. c = { 'request': Mock(path='yermom', GET=Mock(urlencode=lambda: '')), 'user': Mock(), 'settings': Mock() } c['request'].user.is_authenticated.return_value = False doc = pq(barometer(c, collection)) eq_(doc('form')[0].action, '/en-US/firefox/users/login?to=yermom') # Mock logged in. c['request'].user.votes.filter.return_value = [Mock(vote=1)] c['request'].user.is_authenticated.return_value = True barometer(c, collection) doc = pq(barometer(c, collection)) eq_( doc('form')[0].action, reverse('collections.vote', args=['clouserw', 'mccrackin', 'up']))
def test_persona_sha512_md5(self): md5 = hashlib.md5('password').hexdigest() hsh = hashlib.sha512(self.bytes_ + md5).hexdigest() u = UserProfile(password='******' % (self.bytes_, hsh)) assert u.check_password('password') is True assert u.has_usable_password() is True
def test_has_anonymous_display_name_no_names(self): user = UserProfile(display_name=None) user.anonymize_username() assert user.has_anonymous_display_name()
def test_has_anonymous_username_both_names_set(self): user = UserProfile(username='******', display_name='Bob Bobbertson') assert not user.has_anonymous_username()
def test_fxa_migrated_not_migrated(self): user = UserProfile(fxa_id=None) assert user.fxa_migrated() is False
def test_get_unfiltered_manager(self): Addon.get_unfiltered_manager() == Addon.unfiltered UserProfile.get_unfiltered_manager() == UserProfile.objects
def test_invalid_old_password(self): u = UserProfile(password=self.utf) assert u.check_password(self.utf) is False assert u.has_usable_password() is True
def test_welcome_name_anonymous(self): user = UserProfile( username='******') assert user.welcome_name == 'Anonymous user bb4f3c'
def test_persona_sha512_base64_maybe_utf8(self): hsh = hashlib.sha512(self.bytes_ + self.utf.encode('utf8')).hexdigest() u = UserProfile(password='******' % (encodestring(self.bytes_), hsh)) assert u.check_password(self.utf) is True assert u.has_usable_password() is True
def test_valid_new_password(self): u = UserProfile() u.set_password(self.utf) assert u.check_password(self.utf) is True assert u.has_usable_password() is True
def test_fxa_migrated_not_migrated_empty_string(self): user = UserProfile(fxa_id='') assert user.fxa_migrated() is False
def test_invalid_new_password(self): u = UserProfile() u.set_password(self.utf) assert u.check_password('wrong') is False assert u.has_usable_password() is True
def test_persona_sha512_base64(self): hsh = hashlib.sha512(self.bytes_ + 'password').hexdigest() u = UserProfile(password='******' % (encodestring(self.bytes_), hsh)) assert u.check_password('password') is True assert u.has_usable_password() is True
def test_has_anonymous_username_no_names(self): user = UserProfile(display_name=None) user.anonymize_username() assert user.has_anonymous_username()
def test_has_anonymous_username_display_name_set(self): user = UserProfile(display_name='Bob Bobbertson') user.anonymize_username() assert user.has_anonymous_username()
def test_welcome_name_anonymous_with_display(self): user = UserProfile(display_name='John Connor') user.anonymize_username() assert user.welcome_name == 'John Connor'
def test_fxa_migrated_migrated(self): user = UserProfile(fxa_id='db27f8') assert user.fxa_migrated() is True
def test_has_anonymous_username_username_set(self): user = UserProfile(username='******', display_name=None) assert not user.has_anonymous_username()
def fake_object(self, data): """Create a fake instance of Addon and related models from ES data.""" obj = Addon(id=data['id'], slug=data['slug']) # Attach base attributes that have the same name/format in ES and in # the model. self._attach_fields( obj, data, ('average_daily_users', 'bayesian_rating', 'created', 'default_locale', 'guid', 'has_eula', 'has_privacy_policy', 'hotness', 'icon_type', 'is_experimental', 'last_updated', 'modified', 'public_stats', 'slug', 'status', 'type', 'view_source', 'weekly_downloads')) # Attach attributes that do not have the same name/format in ES. obj.tag_list = data['tags'] obj.disabled_by_user = data['is_disabled'] # Not accurate, but enough. obj.all_categories = [ CATEGORIES_BY_ID[cat_id] for cat_id in data.get('category', []) ] # Attach translations (they require special treatment). self._attach_translations(obj, data, self.translated_fields) # Attach related models (also faking them). `current_version` is a # property we can't write to, so we use the underlying field which # begins with an underscore. `current_beta_version` and # `latest_unlisted_version` are writeable cached_property so we can # directly write to them. obj.current_beta_version = self.fake_version_object( obj, data.get('current_beta_version'), amo.RELEASE_CHANNEL_LISTED) obj._current_version = self.fake_version_object( obj, data.get('current_version'), amo.RELEASE_CHANNEL_LISTED) obj.latest_unlisted_version = self.fake_version_object( obj, data.get('latest_unlisted_version'), amo.RELEASE_CHANNEL_UNLISTED) data_authors = data.get('listed_authors', []) obj.listed_authors = [ UserProfile(id=data_author['id'], display_name=data_author['name'], username=data_author['username']) for data_author in data_authors ] # We set obj.all_previews to the raw preview data because # ESPreviewSerializer will handle creating the fake Preview object # for us when its to_representation() method is called. obj.all_previews = data.get('previews', []) obj.average_rating = data.get('ratings', {}).get('average') obj.total_reviews = data.get('ratings', {}).get('count') if data['type'] == amo.ADDON_PERSONA: persona_data = data.get('persona') if persona_data: obj.persona = Persona( addon=obj, accentcolor=persona_data['accentcolor'], display_username=persona_data['author'], header=persona_data['header'], footer=persona_data['footer'], # "New" Persona do not have a persona_id, it's a relic from # old ones. persona_id=0 if persona_data['is_new'] else 42, textcolor=persona_data['textcolor']) else: # Sadly, https://code.djangoproject.com/ticket/14368 prevents # us from setting obj.persona = None. This is fixed in # Django 1.9, but in the meantime, work around it by creating # a Persona instance with a custom attribute indicating that # it should not be used. obj.persona = Persona() obj.persona._broken = True return obj