Exemplo n.º 1
0
    def test_user_review_history(self):
        self.theme_factory()

        reviewer = self.create_and_become_reviewer()

        res = self.client.get(reverse('editors.themes.history'))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('tbody tr').length == 0

        theme = Persona.objects.all()[0]
        for x in range(3):
            ActivityLog.create(
                amo.LOG.THEME_REVIEW, theme.addon, user=reviewer,
                details={'action': rvw.ACTION_APPROVE,
                         'comment': '', 'reject_reason': ''})

        res = self.client.get(reverse('editors.themes.history'))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('tbody tr').length == 3

        res = self.client.get(reverse('editors.themes.logs'))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('tbody tr').length == 3 * 2  # Double for comment rows.
Exemplo n.º 2
0
 def test_version_log(self):
     version = Version.objects.all()[0]
     ActivityLog.create(amo.LOG.REJECT_VERSION, version.addon, version,
                        user=self.request.user)
     entries = ActivityLog.objects.for_version(version)
     assert len(entries) == 1
     assert version.get_url_path() in unicode(entries[0])
Exemplo n.º 3
0
    def test_last_known_activity_time(self):
        someone_else = user_factory(username='******')
        addon = addon_factory()

        model_admin = UserAdmin(UserProfile, admin.site)
        assert six.text_type(
            model_admin.last_known_activity_time(self.user)) == ''

        # Add various activities. They will be attached to whatever user is
        # set in the thread global at the time, so set that in advance.
        core.set_user(self.user)
        expected_date = self.days_ago(1)
        activity = ActivityLog.create(amo.LOG.CREATE_ADDON, addon)
        activity.update(created=self.days_ago(2))
        activity.userlog_set.update(created=self.days_ago(2))

        activity = ActivityLog.create(amo.LOG.EDIT_PROPERTIES, addon)
        activity.update(created=expected_date)
        activity.userlog_set.update(created=expected_date)

        assert activity.reload().created == expected_date

        # Create another activity, more recent, attached to a different user.
        core.set_user(someone_else)
        activity = ActivityLog.create(amo.LOG.EDIT_PROPERTIES, addon)

        expected_result = DateFormat(expected_date).format(
            settings.DATETIME_FORMAT)

        assert (
            six.text_type(model_admin.last_known_activity_time(self.user)) ==
            expected_result)
Exemplo n.º 4
0
    def save(self, *args, **kw):
        """Save all form data.

        This will only create a new license if it's not one of the builtin
        ones.

        Keyword arguments

        **log=True**
            Set to False if you do not want to log this action for display
            on the developer dashboard.
        """
        log = kw.pop('log', True)
        changed = self.changed_data

        builtin = self.cleaned_data['builtin']
        if builtin == '':  # No license chosen, it must be an unlisted add-on.
            return
        if builtin != License.OTHER:
            # We're dealing with a builtin license, there is no modifications
            # allowed to it, just return it.
            license = License.objects.get(builtin=builtin)
        else:
            # We're not dealing with a builtin license, so save it to the
            # database.
            license = super(LicenseForm, self).save(*args, **kw)

        if self.version:
            if changed or license != self.version.license:
                self.version.update(license=license)
                if log:
                    ActivityLog.create(amo.LOG.CHANGE_LICENSE, license,
                                       self.version.addon)
        return license
Exemplo n.º 5
0
 def test_hidden(self):
     version = Version.objects.create(addon=self.addon)
     ActivityLog.create(amo.LOG.COMMENT_VERSION, self.addon, version)
     res = self.get_response(addon=self.addon.id)
     key = RssKey.objects.get()
     res = self.get_response(privaterss=key.key)
     assert b'<title>Comment on' not in res.content
Exemplo n.º 6
0
 def test_json_failboat(self):
     addon = Addon.objects.get()
     ActivityLog.create(amo.LOG.CREATE_ADDON, addon)
     entry = ActivityLog.objects.get()
     entry._arguments = 'failboat?'
     entry.save()
     assert entry.arguments is None
Exemplo n.º 7
0
 def test_addon_logging_pseudo(self):
     """
     If we are given (Addon, 3615) it should log in the AddonLog as well.
     """
     addon = Addon.objects.get()
     ActivityLog.create(amo.LOG.CREATE_ADDON, (Addon, addon.id))
     assert AddonLog.objects.count() == 1
Exemplo n.º 8
0
    def test_normal(self):
        addon = addon_factory()
        author = user_factory(username=u'Authør')
        AddonUser.objects.create(addon=addon, user=author)
        # Add a pending info request expiring soon.
        flags = AddonReviewerFlags.objects.create(
            addon=addon,
            pending_info_request=datetime.now() + timedelta(hours=23),
            notified_about_expiring_info_request=False)
        # Create reviewer and staff users, and create the request for info
        # activity. Neither the reviewer nor the staff user should be cc'ed.
        reviewer = user_factory(username=u'Revièwer')
        self.grant_permission(reviewer, 'Addons:Review')
        ActivityLog.create(
            amo.LOG.REQUEST_INFORMATION, addon, addon.current_version,
            user=reviewer, details={'comments': u'Fly you fôöls!'})
        staff = user_factory(username=u'Staff Ûser')
        self.grant_permission(staff, 'Some:Perm', name=ACTIVITY_MAIL_GROUP)

        # Fire the command.
        call_command('send_info_request_last_warning_notifications')

        assert len(mail.outbox) == 1
        msg = mail.outbox[0]
        assert msg.to == [author.email]
        assert msg.subject == u'Mozilla Add-ons: Action Required for %s %s' % (
            addon.name, addon.current_version.version)
        assert 'an issue when reviewing ' in msg.body
        assert 'within one (1) day' in msg.body

        flags.reload()
        assert flags.notified_about_expiring_info_request is True
Exemplo n.º 9
0
def addon_manage(request, addon):
    form = AddonStatusForm(request.POST or None, instance=addon)
    pager = amo.utils.paginate(
        request, Version.unfiltered.filter(addon=addon), 30)
    # A list coercion so this doesn't result in a subquery with a LIMIT which
    # MySQL doesn't support (at this time).
    versions = list(pager.object_list)
    files = File.objects.filter(version__in=versions).select_related('version')
    formset = FileFormSet(request.POST or None, queryset=files)

    if form.is_valid() and formset.is_valid():
        if 'status' in form.changed_data:
            ActivityLog.create(amo.LOG.CHANGE_STATUS, addon,
                               form.cleaned_data['status'])
            log.info('Addon "%s" status changed to: %s' % (
                addon.slug, form.cleaned_data['status']))
            form.save()

        for form in formset:
            if 'status' in form.changed_data:
                log.info('Addon "%s" file (ID:%d) status changed to: %s' % (
                    addon.slug, form.instance.id, form.cleaned_data['status']))
                form.save()
        return redirect('zadmin.addon_manage', addon.slug)

    # Build a map from file.id to form in formset for precise form display
    form_map = dict((form.instance.id, form) for form in formset.forms)
    # A version to file map to avoid an extra query in the template
    file_map = {}
    for file in files:
        file_map.setdefault(file.version_id, []).append(file)

    return render(request, 'zadmin/addon_manage.html', {
        'addon': addon, 'pager': pager, 'versions': versions, 'form': form,
        'formset': formset, 'form_map': form_map, 'file_map': file_map})
Exemplo n.º 10
0
    def save(self):
        action = self.cleaned_data['action']
        comment = self.cleaned_data.get('comment')
        reject_reason = self.cleaned_data.get('reject_reason')
        theme = self.cleaned_data['theme']

        is_rereview = (
            theme.rereviewqueuetheme_set.exists() and
            theme.addon.status not in (amo.STATUS_PENDING,
                                       amo.STATUS_REVIEW_PENDING))

        theme_lock = ThemeLock.objects.get(theme=self.cleaned_data['theme'])

        mail_and_log = True
        if action == amo.ACTION_APPROVE:
            if is_rereview:
                approve_rereview(theme)
            theme.addon.update(status=amo.STATUS_PUBLIC)
            theme.approve = datetime.datetime.now()
            theme.save()

        elif action in (amo.ACTION_REJECT, amo.ACTION_DUPLICATE):
            if is_rereview:
                reject_rereview(theme)
            else:
                theme.addon.update(status=amo.STATUS_REJECTED)

        elif action == amo.ACTION_FLAG:
            if is_rereview:
                mail_and_log = False
            else:
                theme.addon.update(status=amo.STATUS_REVIEW_PENDING)

        elif action == amo.ACTION_MOREINFO:
            if not is_rereview:
                theme.addon.update(status=amo.STATUS_REVIEW_PENDING)

        if mail_and_log:
            send_mail(self.cleaned_data, theme_lock)

            # Log.
            ActivityLog.create(
                amo.LOG.THEME_REVIEW, theme.addon, details={
                    'theme': theme.addon.name.localized_string,
                    'action': action,
                    'reject_reason': reject_reason,
                    'comment': comment}, user=theme_lock.reviewer)
            log.info('%sTheme %s (%s) - %s' % (
                '[Rereview] ' if is_rereview else '', theme.addon.name,
                theme.id, action))

        score = 0
        if action in (amo.ACTION_REJECT, amo.ACTION_DUPLICATE,
                      amo.ACTION_APPROVE):
            score = ReviewerScore.award_points(
                theme_lock.reviewer, theme.addon, theme.addon.status)
        theme_lock.delete()

        return score
Exemplo n.º 11
0
 def test_basic(self):
     addon = Addon.objects.get()
     ActivityLog.create(amo.LOG.CREATE_ADDON, addon)
     entries = ActivityLog.objects.for_addons(addon)
     assert len(entries) == 1
     assert entries[0].arguments[0] == addon
     for x in ('Delicious Bookmarks', 'was created.'):
         assert x in unicode(entries[0])
Exemplo n.º 12
0
 def test_tag_no_match(self):
     addon = Addon.objects.get()
     tag = Tag.objects.create(tag_text='http://foo.com')
     ActivityLog.create(amo.LOG.ADD_TAG, addon, tag)
     log = ActivityLog.objects.get()
     text = amo.utils.from_string('<p>{{ log }}</p>').render({'log': log})
     # There should only be one a, the link to the addon, but no tag link.
     assert len(pq(text)('a')) == 1
Exemplo n.º 13
0
 def test_pseudo_objects(self):
     """
     If we give an argument of (Addon, 3615) ensure we get
     Addon.objects.get(pk=3615).
     """
     activity_log = ActivityLog()
     activity_log.arguments = [(Addon, 3615)]
     assert activity_log.arguments[0] == Addon.objects.get(pk=3615)
Exemplo n.º 14
0
 def disable(self, request, **kwargs):
     addon = get_object_or_404(Addon, pk=kwargs['pk'])
     ActivityLog.create(amo.LOG.CHANGE_STATUS, addon, amo.STATUS_DISABLED)
     self.log.info('Addon "%s" status changed to: %s',
                   addon.slug, amo.STATUS_DISABLED)
     addon.update(status=amo.STATUS_DISABLED)
     addon.update_version()
     return Response(status=status.HTTP_202_ACCEPTED)
Exemplo n.º 15
0
    def save(self):
        addon = self.instance
        persona = addon.persona
        data = self.cleaned_data

        # Update Persona-specific data.
        persona_data = {
            'license': int(data['license']),
            'accentcolor': data['accentcolor'].lstrip('#'),
            'textcolor': data['textcolor'].lstrip('#'),
            'author': self.request.user.username,
            'display_username': self.request.user.name
        }
        changed = False
        for k, v in persona_data.iteritems():
            if v != getattr(persona, k):
                changed = True
                setattr(persona, k, v)
        if changed:
            persona.save()

        if self.changed_data:
            ActivityLog.create(amo.LOG.EDIT_PROPERTIES, addon)
        self.instance.modified = datetime.now()

        # Update Addon-specific data.
        changed = (
            set(self.old_tags) != data['tags'] or  # Check if tags changed.
            self.initial['slug'] != data['slug'] or  # Check if slug changed.
            transfield_changed('description', self.initial, data) or
            transfield_changed('name', self.initial, data))
        if changed:
            # Only save if addon data changed.
            super(EditThemeForm, self).save()

        # Update tags.
        tags_new = data['tags']
        tags_old = [slugify(t, spaces=True) for t in self.old_tags]
        # Add new tags.
        for t in set(tags_new) - set(tags_old):
            Tag(tag_text=t).save_tag(addon)
        # Remove old tags.
        for t in set(tags_old) - set(tags_new):
            Tag(tag_text=t).remove_tag(addon)

        # Update category.
        if data['category'].id != self.initial['category']:
            addon_cat = addon.addoncategory_set.all()[0]
            addon_cat.category = data['category']
            addon_cat.save()

        # Theme reupload.
        if not addon.is_pending():
            if data['header_hash']:
                addons_tasks.save_theme_reupload.delay(
                    data['header_hash'], addon.pk)

        return data
Exemplo n.º 16
0
 def test_we_only_email_devs_that_need_emailing(self):
     # Doesn't matter the reason, but this addon doesn't get an email.
     ActivityLog.create(
         amo.LOG.PRELIMINARY_ADDON_MIGRATED, self.addon,
         details={'email': False}, user=self.addon.authors.get())
     res = self.post(recipients='depreliminary')
     self.assertNoFormErrors(res)
     self.assert3xx(res, reverse('zadmin.email_devs'))
     assert len(mail.outbox) == 0
Exemplo n.º 17
0
 def ban_action(self, request, qs):
     users = []
     UserProfile.ban_and_disable_related_content_bulk(qs)
     for obj in qs:
         ActivityLog.create(amo.LOG.ADMIN_USER_BANNED, obj)
         users.append(force_text(obj))
     kw = {'users': u', '.join(users)}
     self.message_user(
         request, ugettext('The users "%(users)s" have been banned.' % kw))
Exemplo n.º 18
0
 def test_version_log_unlisted_addon(self):
     version = Version.objects.all()[0]
     # Get the url before the addon is changed to unlisted.
     url_path = version.get_url_path()
     self.make_addon_unlisted(version.addon)
     ActivityLog.create(amo.LOG.REJECT_VERSION, version.addon, version,
                        user=self.request.user)
     entries = ActivityLog.objects.for_version(version)
     assert len(entries) == 1
     assert url_path not in unicode(entries[0])
Exemplo n.º 19
0
 def enable(self, request, **kwargs):
     addon = get_object_or_404(Addon, pk=kwargs['pk'])
     ActivityLog.create(amo.LOG.CHANGE_STATUS, addon, amo.STATUS_PUBLIC)
     self.log.info('Addon "%s" status changed to: %s',
                   addon.slug, amo.STATUS_PUBLIC)
     addon.update(status=amo.STATUS_PUBLIC)
     # Call update_status() to fix the status if the add-on is not actually
     # in a state that allows it to be public.
     addon.update_status()
     return Response(status=status.HTTP_202_ACCEPTED)
Exemplo n.º 20
0
 def test_addon_log_unlisted_addon(self):
     addon = Addon.objects.get()
     # Get the url before the addon is changed to unlisted.
     url_path = addon.get_url_path()
     self.make_addon_unlisted(addon)
     # Delete the status change log entry from making versions unlisted.
     ActivityLog.objects.for_addons(addon).delete()
     ActivityLog.create(amo.LOG.CREATE_ADDON, (Addon, addon.id))
     entries = ActivityLog.objects.for_addons(addon)
     assert len(entries) == 1
     assert url_path not in unicode(entries[0])
Exemplo n.º 21
0
 def test_get_index(self):
     # Add fake log that would be shown in the index page.
     user = UserProfile.objects.get(email='*****@*****.**')
     ActivityLog.create(
         amo.LOG.GROUP_USER_ADDED, user.groups.latest('pk'), user,
         user=user)
     url = reverse('zadmin.index')
     response = self.client.get(url, follow=True)
     assert response.status_code == 200
     assert response.context['user'].username == 'admin'
     assert response.context['user'].email == '*****@*****.**'
Exemplo n.º 22
0
 def test_depreliminary_addon_devs(self):
     # We just need a user for the log(), it would normally be task user.
     ActivityLog.create(
         amo.LOG.PRELIMINARY_ADDON_MIGRATED, self.addon,
         details={'email': True}, user=self.addon.authors.get())
     res = self.post(recipients='depreliminary')
     self.assertNoFormErrors(res)
     self.assert3xx(res, reverse('zadmin.email_devs'))
     assert len(mail.outbox) == 1
     assert mail.outbox[0].to == ['*****@*****.**']
     assert mail.outbox[0].from_email == settings.DEFAULT_FROM_EMAIL
Exemplo n.º 23
0
 def flags(self, request, **kwargs):
     addon = get_object_or_404(Addon, pk=kwargs['pk'])
     instance, _ = AddonReviewerFlags.objects.get_or_create(addon=addon)
     serializer = AddonReviewerFlagsSerializer(
         instance, data=request.data, partial=True)
     serializer.is_valid(raise_exception=True)
     # If pending info request was modified, log it.
     if 'pending_info_request' in serializer.initial_data:
         ActivityLog.create(amo.LOG.ADMIN_ALTER_INFO_REQUEST, addon)
     serializer.save()
     return Response(serializer.data)
Exemplo n.º 24
0
    def save(self, commit=True):
        ob = super(PolicyForm, self).save(commit)
        for k, field in (('has_eula', 'eula'),
                         ('has_priv', 'privacy_policy')):
            if not self.cleaned_data[k]:
                delete_translation(self.instance, field)

        if 'privacy_policy' in self.changed_data:
            ActivityLog.create(amo.LOG.CHANGE_POLICY, self.addon,
                               self.instance)

        return ob
Exemplo n.º 25
0
 def test_beta_signed_events_validation_ignored(self):
     addon = Addon.objects.get()
     file_ = addon.versions.first().files.first()
     # Signed beta file which passed validation.
     ActivityLog.create(amo.LOG.BETA_SIGNED, file_)
     log = ActivityLog.objects.beta_signed_events().first().to_string()
     link = pq(log)('a')
     assert len(link) == 1
     assert link[0].attrib['href'] == reverse('files.list', args=[file_.pk])
     msg = '<a href="{0}">{1}</a> (validation ignored) was signed.'.format(
         reverse('files.list', args=[file_.pk]), file_.filename)
     assert log == msg
Exemplo n.º 26
0
 def test_dont_show_request_for_information_if_none_pending(self):
     self.user = UserProfile.objects.latest('pk')
     ActivityLog.create(
         amo.LOG.REVIEWER_REPLY_VERSION, self.addon, self.version,
         user=self.user, details={'comments': 'this should not be shown'})
     ActivityLog.create(
         amo.LOG.REQUEST_INFORMATION, self.addon, self.version,
         user=self.user, details={'comments': 'this is an info request'})
     response = self.client.get(self.url)
     assert response.status_code == 200
     assert 'this should not be shown' not in response.content
     assert 'this is an info request' not in response.content
Exemplo n.º 27
0
 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
Exemplo n.º 28
0
 def save(self, *args, **kw):
     profile = super(AdminUserEditForm, self).save(log_for_developer=False)
     if self.cleaned_data['anonymize']:
         ActivityLog.create(amo.LOG.ADMIN_USER_ANONYMIZED, self.instance,
                            self.cleaned_data['admin_log'])
         profile.delete()  # This also logs
     else:
         ActivityLog.create(amo.LOG.ADMIN_USER_EDITED, self.instance,
                            self.cleaned_data['admin_log'],
                            details=self.changes())
         log.info('Admin edit user: %s changed fields: %s' %
                  (self.instance, self.changed_fields()))
     return profile
Exemplo n.º 29
0
    def test_dashboard_review_counts(self):
        theme = addon_factory(type=amo.ADDON_PERSONA)
        for i in range(3):
            ActivityLog.create(amo.LOG.THEME_REVIEW, theme,
                               user=UserProfile.objects.get())

        r = home(self.request)
        assert r.status_code == 200

        doc = pq(r.content)
        # Total reviews.
        assert doc('.editor-stats-table:first-child td.int').text() == '3'
        # Reviews monthly.
        assert doc('.editor-stats-table:last-child td.int').text() == '3'
Exemplo n.º 30
0
def log_and_notify(action, comments, note_creator, version, perm_setting=None,
                   detail_kwargs=None):
    """Record an action through ActivityLog and notify relevant users about it.
    """
    log_kwargs = {
        'user': note_creator,
        'created': datetime.now(),
    }
    if detail_kwargs is None:
        detail_kwargs = {}
    if comments:
        detail_kwargs['version'] = version.version
        detail_kwargs['comments'] = comments
    if detail_kwargs:
        log_kwargs['details'] = detail_kwargs

    note = ActivityLog.create(action, version.addon, version, **log_kwargs)
    if not note:
        return

    notify_about_activity_log(
        version.addon, version, note, perm_setting=perm_setting)

    if action == amo.LOG.DEVELOPER_REPLY_VERSION:
        # When a developer repies by email, we automatically clear the
        # corresponding info request.
        AddonReviewerFlags.objects.update_or_create(
            addon=version.addon, defaults={'pending_info_request': None}
        )

    return note
Exemplo n.º 31
0
    def test_known_ip_adresses(self):
        self.user.update(last_login_ip='127.1.2.3')
        Rating.objects.create(addon=addon_factory(),
                              user=self.user,
                              ip_address='127.1.2.3')
        dummy_addon = addon_factory()
        Rating.objects.create(
            addon=dummy_addon,
            version=dummy_addon.current_version,
            user=self.user,
            ip_address='128.1.2.3',
        )
        Rating.objects.create(
            addon=dummy_addon,
            version=version_factory(addon=dummy_addon),
            user=self.user,
            ip_address='129.1.2.4',
        )
        Rating.objects.create(addon=addon_factory(),
                              user=self.user,
                              ip_address='130.1.2.4')
        Rating.objects.create(addon=addon_factory(),
                              user=self.user,
                              ip_address='130.1.2.4')
        Rating.objects.create(addon=dummy_addon,
                              user=user_factory(),
                              ip_address='255.255.0.0')
        with core.override_remote_addr('15.16.23.42'):
            ActivityLog.create(amo.LOG.ADD_VERSION,
                               dummy_addon,
                               user=self.user)
        UserRestrictionHistory.objects.create(user=self.user,
                                              last_login_ip='4.8.15.16')
        UserRestrictionHistory.objects.create(user=self.user,
                                              ip_address='172.0.0.2')
        model_admin = UserAdmin(UserProfile, admin.site)
        doc = pq(model_admin.known_ip_adresses(self.user))
        result = doc('ul li').text().split()
        assert len(result) == 7
        assert set(result) == {
            '130.1.2.4',
            '128.1.2.3',
            '129.1.2.4',
            '127.1.2.3',
            '15.16.23.42',
            '172.0.0.2',
            '4.8.15.16',
        }

        # Duplicates are ignored
        Rating.objects.create(
            addon=dummy_addon,
            version=version_factory(addon=dummy_addon),
            user=self.user,
            ip_address='127.1.2.3',
        )
        with core.override_remote_addr('172.0.0.2'):
            ActivityLog.create(amo.LOG.ADD_VERSION,
                               dummy_addon,
                               user=self.user)
        UserRestrictionHistory.objects.create(user=self.user,
                                              last_login_ip='15.16.23.42')
        UserRestrictionHistory.objects.create(user=self.user,
                                              ip_address='4.8.15.16')
        doc = pq(model_admin.known_ip_adresses(self.user))
        result = doc('ul li').text().split()
        assert len(result) == 7
        assert set(result) == {
            '130.1.2.4',
            '128.1.2.3',
            '129.1.2.4',
            '127.1.2.3',
            '15.16.23.42',
            '172.0.0.2',
            '4.8.15.16',
        }
Exemplo n.º 32
0
 def delete_model(self, request, obj):
     args = [amo.LOG.BLOCKLIST_BLOCK_DELETED, obj.addon, obj.guid]
     super().delete_model(request, obj)
     ActivityLog.create(*args)
Exemplo n.º 33
0
 def log_rating(self, num):
     rating = Rating(addon=self.addon)
     for i in xrange(num):
         ActivityLog.create(amo.LOG.ADD_RATING, self.addon, rating)
Exemplo n.º 34
0
 def log_tag(self, num, prefix='foo'):
     for i in xrange(num):
         tag = Tag.objects.create(tag_text='%s %d' % (prefix, i))
         ActivityLog.create(amo.LOG.ADD_TAG, self.addon, tag)
Exemplo n.º 35
0
def log_create(action, *args, **kw):
    """Use this if importing ActivityLog causes a circular import."""
    from olympia.activity.models import ActivityLog
    return ActivityLog.create(action, *args, **kw)
Exemplo n.º 36
0
 def test_bad_arguments(self):
     activity_log = ActivityLog()
     activity_log.arguments = []
     activity_log.action = amo.LOG.ADD_USER_WITH_ROLE.id
     assert activity_log.to_string() == 'Something magical happened.'
Exemplo n.º 37
0
 def test_no_user(self):
     core.set_user(None)
     count = ActivityLog.objects.count()
     ActivityLog.create(amo.LOG.CUSTOM_TEXT, 'hi')
     assert count == ActivityLog.objects.count()
Exemplo n.º 38
0
def log_and_notify(action,
                   comments,
                   note_creator,
                   version,
                   perm_setting=None,
                   detail_kwargs=None):
    log_kwargs = {
        'user': note_creator,
        'created': datetime.datetime.now(),
    }
    if detail_kwargs is None:
        detail_kwargs = {}
    if comments:
        detail_kwargs['version'] = version.version
        detail_kwargs['comments'] = comments
    else:
        # Just use the name of the action if no comments provided.  Alas we
        # can't know the locale of recipient, and our templates are English
        # only so prevent language jumble by forcing into en-US.
        with no_translation():
            comments = '%s' % action.short
    if detail_kwargs:
        log_kwargs['details'] = detail_kwargs

    note = ActivityLog.create(action, version.addon, version, **log_kwargs)
    if not note:
        return

    # Collect reviewers involved with this version.
    review_perm = (amo.permissions.ADDONS_REVIEW
                   if version.channel == amo.RELEASE_CHANNEL_LISTED else
                   amo.permissions.ADDONS_REVIEW_UNLISTED)
    log_users = {
        alog.user
        for alog in ActivityLog.objects.for_version(version)
        if acl.action_allowed_user(alog.user, review_perm)
    }
    # Collect add-on authors (excl. the person who sent the email.)
    addon_authors = set(version.addon.authors.all()) - {note_creator}
    # Collect staff that want a copy of the email
    staff = set(UserProfile.objects.filter(groups__name=ACTIVITY_MAIL_GROUP))
    # If task_user doesn't exist that's no big issue (i.e. in tests)
    try:
        task_user = {get_task_user()}
    except UserProfile.DoesNotExist:
        task_user = set()
    # Collect reviewers on the thread (excl. the email sender and task user for
    # automated messages).
    reviewers = log_users - addon_authors - task_user - {note_creator}
    staff_cc = staff - reviewers - addon_authors - task_user - {note_creator}
    author_context_dict = {
        'name': version.addon.name,
        'number': version.version,
        'author': note_creator.name,
        'comments': comments,
        'url': absolutify(version.addon.get_dev_url('versions')),
        'SITE_URL': settings.SITE_URL,
        'email_reason': 'you are an author of this add-on'
    }

    reviewer_context_dict = author_context_dict.copy()
    reviewer_context_dict['url'] = absolutify(
        reverse('editors.review',
                kwargs={
                    'addon_id': version.addon.pk,
                    'channel': amo.CHANNEL_CHOICES_API[version.channel]
                },
                add_prefix=False))
    reviewer_context_dict['email_reason'] = 'you reviewed this add-on'

    staff_cc_context_dict = reviewer_context_dict.copy()
    staff_cc_context_dict['email_reason'] = (
        'you are member of the activity email cc group')

    # Not being localised because we don't know the recipients locale.
    with translation.override('en-US'):
        subject = u'Mozilla Add-ons: %s %s' % (version.addon.name,
                                               version.version)
    template = template_from_user(note_creator, version)
    from_email = formataddr((note_creator.name, NOTIFICATIONS_FROM_EMAIL))
    send_activity_mail(subject, template.render(author_context_dict), version,
                       addon_authors, from_email, note.id, perm_setting)

    send_activity_mail(subject, template.render(reviewer_context_dict),
                       version, reviewers, from_email, note.id, perm_setting)

    send_activity_mail(subject, template.render(staff_cc_context_dict),
                       version, staff_cc, from_email, note.id, perm_setting)

    if action == amo.LOG.DEVELOPER_REPLY_VERSION:
        version.update(has_info_request=False)

    return note
Exemplo n.º 39
0
 def test_log_not_admin(self):
     ActivityLog.create(amo.LOG.EDIT_VERSION, Addon.objects.get())
     assert len(ActivityLog.objects.admin_events()) == 0
     assert len(ActivityLog.objects.for_developer()) == 1
Exemplo n.º 40
0
 def test_not_total(self):
     ActivityLog.create(amo.LOG.EDIT_VERSION, Addon.objects.get())
     assert len(ActivityLog.objects.total_reviews()) == 0
Exemplo n.º 41
0
 def test_review_count(self):
     ActivityLog.create(amo.LOG.APPROVE_VERSION, Addon.objects.get())
     result = ActivityLog.objects.monthly_reviews()
     assert len(result) == 1
     assert result[0]['approval_count'] == 1
     assert result[0]['user'] == self.user.pk
Exemplo n.º 42
0
 def add_approve_logs(self, count):
     for x in range(0, count):
         ActivityLog.create(amo.LOG.APPROVE_VERSION, Addon.objects.get())
Exemplo n.º 43
0
 def test_output(self):
     ActivityLog.create(amo.LOG.CUSTOM_TEXT, 'hi there')
     entry = ActivityLog.objects.get()
     assert unicode(entry) == 'hi there'
Exemplo n.º 44
0
def log_and_notify(action, comments, note_creator, version):
    log_kwargs = {
        'user': note_creator,
        'created': datetime.datetime.now(),
    }
    if comments:
        log_kwargs['details'] = {
            'comments': comments,
            'version': version.version
        }
    else:
        # Just use the name of the action if no comments provided.  Alas we
        # can't know the locale of recipient, and our templates are English
        # only so prevent language jumble by forcing into en-US.
        with no_translation():
            comments = '%s' % action.short
    note = ActivityLog.create(action, version.addon, version, **log_kwargs)

    # Collect reviewers involved with this version.
    review_perm = ('Review' if version.channel == amo.RELEASE_CHANNEL_LISTED
                   else 'ReviewUnlisted')
    log_users = {
        alog.user
        for alog in ActivityLog.objects.for_version(version)
        if acl.action_allowed_user(alog.user, 'Addons', review_perm)
    }
    # Collect add-on authors (excl. the person who sent the email.)
    addon_authors = set(version.addon.authors.all()) - {note_creator}
    # Collect staff that want a copy of the email
    staff_cc = set(
        UserProfile.objects.filter(groups__name=ACTIVITY_MAIL_GROUP))
    # If task_user doesn't exist that's no big issue (i.e. in tests)
    try:
        task_user = {get_task_user()}
    except UserProfile.DoesNotExist:
        task_user = set()
    # Collect reviewers on the thread (excl. the email sender and task user for
    # automated messages).
    reviewers = ((log_users | staff_cc) - addon_authors - task_user -
                 {note_creator})
    author_context_dict = {
        'name': version.addon.name,
        'number': version.version,
        'author': note_creator.name,
        'comments': comments,
        'url': absolutify(version.addon.get_dev_url('versions')),
        'SITE_URL': settings.SITE_URL,
    }
    reviewer_context_dict = author_context_dict.copy()
    reviewer_context_dict['url'] = absolutify(
        reverse('editors.review', args=[version.addon.pk], add_prefix=False))

    # Not being localised because we don't know the recipients locale.
    with translation.override('en-US'):
        subject = u'Mozilla Add-ons: %s %s %s' % (
            version.addon.name, version.version, action.short)
    template = loader.get_template('activity/emails/developer.txt')
    send_activity_mail(subject, template.render(Context(author_context_dict)),
                       version, addon_authors, settings.EDITORS_EMAIL)
    send_activity_mail(subject,
                       template.render(Context(reviewer_context_dict)),
                       version, reviewers, settings.EDITORS_EMAIL)
    return note
Exemplo n.º 45
0
def sign_addons(addon_ids, force=False, send_emails=True, **kw):
    """Used to sign all the versions of an addon.

    This is used in the 'process_addons --task resign_addons_for_cose'
    management command.

    This is also used to resign some promoted addons after they've been added
    to a group (or paid).

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mechanism picks this new signed version and
    installs it.
    """
    log.info(f'[{len(addon_ids)}] Signing addons.')

    mail_subject, mail_message = MAIL_COSE_SUBJECT, MAIL_COSE_MESSAGE

    # query everything except for search-plugins as they're generally
    # not signed
    current_versions = Addon.objects.filter(id__in=addon_ids).values_list(
        '_current_version', flat=True
    )
    qset = Version.objects.filter(id__in=current_versions)

    addons_emailed = set()
    task_user = get_task_user()

    for version in qset:
        file_obj = version.file
        # We only sign files that have been reviewed
        if file_obj.status not in amo.REVIEWED_STATUSES:
            log.info(
                'Not signing addon {}, version {} (no files)'.format(
                    version.addon, version
                )
            )
            continue

        log.info(f'Signing addon {version.addon}, version {version}')
        bumped_version_number = get_new_version_number(version.version)
        did_sign = False  # Did we sign at the file?

        if not os.path.isfile(file_obj.file_path):
            log.info(f'File {file_obj.pk} does not exist, skip')
            continue

        # Save the original file, before bumping the version.
        backup_path = f'{file_obj.file_path}.backup_signature'
        shutil.copy(file_obj.file_path, backup_path)

        try:
            # Need to bump the version (modify manifest file)
            # before the file is signed.
            update_version_number(file_obj, bumped_version_number)
            did_sign = bool(sign_file(file_obj))
            if not did_sign:  # We didn't sign, so revert the version bump.
                shutil.move(backup_path, file_obj.file_path)
        except Exception:
            log.error(f'Failed signing file {file_obj.pk}', exc_info=True)
            # Revert the version bump, restore the backup.
            shutil.move(backup_path, file_obj.file_path)

        # Now update the Version model, if we signed at least one file.
        if did_sign:
            previous_version_str = str(version.version)
            version.update(version=bumped_version_number)
            addon = version.addon
            ActivityLog.create(
                amo.LOG.VERSION_RESIGNED,
                addon,
                version,
                previous_version_str,
                user=task_user,
            )
            if send_emails and addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = AddonUser.objects.filter(
                    role=amo.AUTHOR_ROLE_OWNER, addon=addon
                ).exclude(user__email__isnull=True)
                emails = qs.values_list('user__email', flat=True)
                subject = mail_subject
                message = mail_message.format(addon=addon.name)
                amo.utils.send_mail(
                    subject,
                    message,
                    recipient_list=emails,
                    headers={'Reply-To': '*****@*****.**'},
                )
                addons_emailed.add(addon.pk)
Exemplo n.º 46
0
    def log_updates(self, num, version_string='1'):
        version = Version.objects.create(version=version_string,
                                         addon=self.addon)

        for i in xrange(num):
            ActivityLog.create(amo.LOG.ADD_VERSION, self.addon, version)
Exemplo n.º 47
0
 def test_addon_log(self):
     addon = Addon.objects.get()
     ActivityLog.create(amo.LOG.CREATE_ADDON, (Addon, addon.id))
     entries = ActivityLog.objects.for_addons(addon)
     assert len(entries) == 1
     assert addon.get_url_path() in unicode(entries[0])
Exemplo n.º 48
0
 def log_status(self, num):
     for i in xrange(num):
         ActivityLog.create(amo.LOG.USER_DISABLE, self.addon)
Exemplo n.º 49
0
 def test_no_arguments(self):
     ActivityLog.create(amo.LOG.CUSTOM_HTML)
     entry = ActivityLog.objects.get()
     assert entry.arguments == []
Exemplo n.º 50
0
 def log_collection(self, num, prefix='foo'):
     for i in xrange(num):
         collection = Collection.objects.create(name='%s %d' % (prefix, i))
         ActivityLog.create(amo.LOG.ADD_TO_COLLECTION, self.addon,
                            collection)
Exemplo n.º 51
0
 def test_user_log(self):
     request = self.request
     ActivityLog.create(amo.LOG.CUSTOM_TEXT, 'hi there')
     entries = ActivityLog.objects.for_user(request.user)
     assert len(entries) == 1
Exemplo n.º 52
0
    def save(self):
        action = self.cleaned_data['action']
        comment = self.cleaned_data.get('comment')
        reject_reason = self.cleaned_data.get('reject_reason')
        theme = self.cleaned_data['theme']

        is_rereview = (theme.rereviewqueuetheme_set.exists()
                       and theme.addon.status
                       not in (amo.STATUS_PENDING, amo.STATUS_REVIEW_PENDING))

        theme_lock = ThemeLock.objects.get(theme=self.cleaned_data['theme'])

        mail_and_log = True
        if action == amo.ACTION_APPROVE:
            if is_rereview:
                approve_rereview(theme)
            theme.addon.update(status=amo.STATUS_PUBLIC)
            theme.approve = datetime.datetime.now()
            theme.save()

        elif action in (amo.ACTION_REJECT, amo.ACTION_DUPLICATE):
            if is_rereview:
                reject_rereview(theme)
            else:
                theme.addon.update(status=amo.STATUS_REJECTED)

        elif action == amo.ACTION_FLAG:
            if is_rereview:
                mail_and_log = False
            else:
                theme.addon.update(status=amo.STATUS_REVIEW_PENDING)

        elif action == amo.ACTION_MOREINFO:
            if not is_rereview:
                theme.addon.update(status=amo.STATUS_REVIEW_PENDING)

        if mail_and_log:
            send_mail(self.cleaned_data, theme_lock)

            # Log.
            ActivityLog.create(amo.LOG.THEME_REVIEW,
                               theme.addon,
                               details={
                                   'theme': theme.addon.name.localized_string,
                                   'action': action,
                                   'reject_reason': reject_reason,
                                   'comment': comment
                               },
                               user=theme_lock.reviewer)
            log.info('%sTheme %s (%s) - %s' %
                     ('[Rereview] ' if is_rereview else '', theme.addon.name,
                      theme.id, action))

        score = 0
        if action in (amo.ACTION_REJECT, amo.ACTION_DUPLICATE,
                      amo.ACTION_APPROVE):
            score = ReviewerScore.award_points(theme_lock.reviewer,
                                               theme.addon, theme.addon.status)
        theme_lock.delete()

        return score
Exemplo n.º 53
0
 def test_not_review_count(self):
     ActivityLog.create(amo.LOG.EDIT_VERSION, Addon.objects.get())
     assert len(ActivityLog.objects.monthly_reviews()) == 0
Exemplo n.º 54
0
    def test_get_unique_good_results(self):
        version_1 = version_factory(addon=addon_factory(), version='1.0')
        ScannerResult.objects.create(scanner=MAD, version=version_1)
        ActivityLog.create(amo.LOG.APPROVE_VERSION, version_1, user=self.user)
        ActivityLog.create(amo.LOG.CONFIRM_AUTO_APPROVED,
                           version_1,
                           user=self.user)
        ActivityLog.create(amo.LOG.CONFIRM_AUTO_APPROVED,
                           version_1,
                           user=self.user)
        version_2 = version_factory(addon=addon_factory(), version='2.0')
        ScannerResult.objects.create(scanner=MAD, version=version_2)
        ActivityLog.create(amo.LOG.APPROVE_VERSION, version_2, user=self.user)
        ActivityLog.create(amo.LOG.CONFIRM_AUTO_APPROVED,
                           version_2,
                           user=self.user)
        ActivityLog.create(amo.LOG.CONFIRM_AUTO_APPROVED,
                           version_2,
                           user=self.user)

        response = self.client.get(f'{self.url}?label=good')
        results = self.assert_json_results(response, expected_results=2)
        assert results[0]['id'] != results[1]['id']
Exemplo n.º 55
0
 def test_review_last_month(self):
     log = ActivityLog.create(amo.LOG.APPROVE_VERSION, Addon.objects.get())
     log.update(created=self.lm)
     assert len(ActivityLog.objects.monthly_reviews()) == 0
Exemplo n.º 56
0
    def test_get(self):
        task_user = user_factory()
        # result labelled as "bad" because its state is TRUE_POSITIVE
        bad_version = version_factory(addon=addon_factory())
        bad_result = ScannerResult.objects.create(scanner=YARA,
                                                  version=bad_version,
                                                  state=TRUE_POSITIVE)
        # result without a version and state is UNKNOWN
        ScannerResult.objects.create(scanner=YARA)
        # true positive, but without a version
        ScannerResult.objects.create(scanner=YARA, state=TRUE_POSITIVE)
        # result labelled as "good" because it has been approved
        good_version_1 = version_factory(addon=addon_factory())
        good_result_1 = ScannerResult.objects.create(scanner=WAT,
                                                     version=good_version_1)
        ActivityLog.create(amo.LOG.APPROVE_VERSION,
                           good_version_1,
                           user=self.user)
        # result labelled as "good" because auto-approve has been confirmed
        good_version_2 = version_factory(addon=addon_factory())
        good_result_2 = ScannerResult.objects.create(scanner=CUSTOMS,
                                                     version=good_version_2)
        ActivityLog.create(amo.LOG.APPROVE_VERSION,
                           good_version_2,
                           user=task_user)
        ActivityLog.create(amo.LOG.CONFIRM_AUTO_APPROVED,
                           good_version_2,
                           user=self.user)
        # Simulate a reviewer who has confirmed auto-approval a second time. We
        # should not return duplicate results.
        ActivityLog.create(amo.LOG.CONFIRM_AUTO_APPROVED,
                           good_version_2,
                           user=self.user)
        # result NOT labelled as "good" because action is not correct.
        version_3 = version_factory(addon=addon_factory())
        ScannerResult.objects.create(scanner=YARA, version=version_3)
        ActivityLog.create(amo.LOG.REJECT_VERSION, version_3, user=self.user)
        # result NOT labelled as "good" because user is TASK_USER_ID
        version_4 = version_factory(addon=addon_factory())
        ScannerResult.objects.create(scanner=YARA, version=version_4)
        ActivityLog.create(amo.LOG.APPROVE_VERSION, version_4, user=task_user)

        with override_settings(TASK_USER_ID=task_user.pk):
            response = self.client.get(self.url)

        assert response.status_code == 200
        results = self.assert_json_results(response, expected_results=3)
        # Force a `label` value so that the serialized (expected) data is
        # accurate. This is needed because `label` is an annotated field
        # created in the QuerySet.
        good_result_2.label = 'good'
        assert results[0] == ScannerResultSerializer(
            instance=good_result_2).data
        # Force a `label` value so that the serialized (expected) data is
        # accurate. This is needed because `label` is an annotated field
        # created in the QuerySet.
        good_result_1.label = 'good'
        assert results[1] == ScannerResultSerializer(
            instance=good_result_1).data
        # Force a `label` value so that the serialized (expected) data is
        # accurate. This is needed because `label` is an annotated field
        # created in the QuerySet.
        bad_result.label = 'bad'
        assert results[2] == ScannerResultSerializer(instance=bad_result).data
Exemplo n.º 57
0
 def test_log_admin(self):
     ActivityLog.create(amo.LOG.OBJECT_EDITED, Addon.objects.get())
     assert len(ActivityLog.objects.admin_events()) == 1
     assert len(ActivityLog.objects.for_developer()) == 0
Exemplo n.º 58
0
 def delete_model(self, request, obj):
     # Deleting a user through the admin also deletes related content
     # produced by that user.
     ActivityLog.create(amo.LOG.ADMIN_USER_ANONYMIZED, obj)
     obj.delete()
Exemplo n.º 59
0
 def save_model(self, request, obj, form, change):
     changes = {k: (form.initial.get(k), form.cleaned_data.get(k))
                for k in form.changed_data}
     ActivityLog.create(amo.LOG.ADMIN_USER_EDITED, obj, details=changes)
     obj.save()
Exemplo n.º 60
0
 def log_creates(self, num, addon=None):
     if not addon:
         addon = self.addon
     for i in xrange(num):
         ActivityLog.create(amo.LOG.CREATE_ADDON, addon)