コード例 #1
0
    def process(self, version):
        """Process a single version, figuring out if it should be auto-approved
        and calling the approval code if necessary."""
        already_locked = AutoApprovalSummary.check_is_locked(version)
        if not already_locked:
            # Lock the addon for ourselves if possible. Even though
            # AutoApprovalSummary.create_summary_for_version() will do
            # call check_is_locked() again later when calculating the verdict,
            # we have to do it now to prevent overwriting an existing lock with
            # our own.
            set_reviewing_cache(version.addon.pk, settings.TASK_USER_ID)
        try:
            log.info('Processing %s version %s...',
                     unicode(version.addon.name), unicode(version.version))
            summary, info = AutoApprovalSummary.create_summary_for_version(
                version, dry_run=self.dry_run)
            log.info('Auto Approval for %s version %s: %s',
                     unicode(version.addon.name), unicode(version.version),
                     summary.get_verdict_display())
            self.stats.update({k: int(v) for k, v in info.items()})
            if summary.verdict == self.successful_verdict:
                self.stats['auto_approved'] += 1
                if summary.verdict == amo.AUTO_APPROVED:
                    self.approve(version)

        except (AutoApprovalNotEnoughFilesError,
                AutoApprovalNoValidationResultError):
            log.info(
                'Version %s was skipped either because it had no '
                'file or because it had no validation attached.', version)
            self.stats['error'] += 1
        finally:
            # Always clear our own lock no matter what happens (but only ours).
            if not already_locked:
                clear_reviewing_cache(version.addon.pk)
コード例 #2
0
    def test_verdict_info_prettifier(self):
        verdict_info = {
            'too_few_approved_updates': True,
            'too_many_average_daily_users': True,
            'uses_content_script_for_all_urls': True,
            'uses_custom_csp': True,
            'uses_native_messaging': True,
            'has_info_request': True,
            'is_locked': True,
            'is_under_admin_review': True,
        }
        result = list(
            AutoApprovalSummary.verdict_info_prettifier(verdict_info))
        assert result == [
            u'Has a pending info request.', u'Is locked by a reviewer.',
            u'Is flagged for admin review.',
            u'Has too few consecutive human-approved updates.',
            u'Has too many daily users.',
            u'Uses a content script for all URLs.', u'Uses a custom CSP.',
            u'Uses nativeMessaging permission.'
        ]

        verdict_info = {
            'too_few_approved_updates': True,
            'uses_content_script_for_all_urls': True,
            'uses_native_messaging': True
        }
        result = list(
            AutoApprovalSummary.verdict_info_prettifier(verdict_info))
        assert result == [
            u'Has too few consecutive human-approved updates.',
            u'Uses a content script for all URLs.',
            u'Uses nativeMessaging permission.'
        ]
コード例 #3
0
    def test_check_is_under_admin_review(self):
        assert AutoApprovalSummary.check_is_under_admin_review(
            self.version) is False

        self.version.addon.update(admin_review=True)
        assert AutoApprovalSummary.check_is_under_admin_review(
            self.version) is True
コード例 #4
0
    def test_check_is_locked(self):
        assert AutoApprovalSummary.check_is_locked(self.version) is False

        set_reviewing_cache(self.version.addon.pk, settings.TASK_USER_ID)
        assert AutoApprovalSummary.check_is_locked(self.version) is False

        set_reviewing_cache(self.version.addon.pk, settings.TASK_USER_ID + 42)
        assert AutoApprovalSummary.check_is_locked(self.version) is True
コード例 #5
0
    def test_check_uses_custom_csp(self):
        assert AutoApprovalSummary.check_uses_custom_csp(self.version) is False

        validation_data = {
            'messages': [{
                'id': ['MANIFEST_CSP'],
            }]
        }
        self.file_validation.update(validation=json.dumps(validation_data))
        assert AutoApprovalSummary.check_uses_custom_csp(self.version) is True
コード例 #6
0
    def test_check_uses_custom_csp_file_validation_missing(self):
        self.file_validation.delete()
        del self.version.all_files
        with self.assertRaises(AutoApprovalNoValidationResultError):
            AutoApprovalSummary.check_uses_custom_csp(self.version)

        # Also happens if only one file is missing validation info.
        self.file_validation = FileValidation.objects.create(
            file=self.version.all_files[0], validation=u'{}')
        del self.version.all_files
        file_factory(version=self.version, status=amo.STATUS_AWAITING_REVIEW)
        with self.assertRaises(AutoApprovalNoValidationResultError):
            AutoApprovalSummary.check_uses_custom_csp(self.version)
コード例 #7
0
    def test_check_uses_native_messaging(self):
        assert (AutoApprovalSummary.check_uses_native_messaging(self.version)
                is False)

        webext_permissions = WebextPermission.objects.create(
            file=self.file, permissions=['foobar'])
        del self.file.webext_permissions_list
        assert (AutoApprovalSummary.check_uses_native_messaging(self.version)
                is False)

        webext_permissions.update(permissions=['nativeMessaging', 'foobar'])
        del self.file.webext_permissions_list
        assert (AutoApprovalSummary.check_uses_native_messaging(self.version)
                is True)
コード例 #8
0
    def test_check_uses_content_script_for_all_urls(self):
        assert AutoApprovalSummary.check_uses_content_script_for_all_urls(
            self.version) is False

        webext_permissions = WebextPermission.objects.create(
            file=self.file, permissions=['https://example.com/*'])
        del self.file.webext_permissions_list
        assert AutoApprovalSummary.check_uses_content_script_for_all_urls(
            self.version) is False

        webext_permissions.update(permissions=['<all_urls>'])
        del self.file.webext_permissions_list
        assert AutoApprovalSummary.check_uses_content_script_for_all_urls(
            self.version) is True
コード例 #9
0
 def test_failed_verdict(self, create_summary_for_version_mock,
                         approve_mock):
     fake_verdict_info = {
         'uses_custom_csp': True,
         'uses_native_messaging': True,
         'uses_content_script_for_all_urls': True,
         'too_many_average_daily_users': True,
         'too_few_approved_updates': True,
     }
     create_summary_for_version_mock.return_value = (AutoApprovalSummary(
         verdict=amo.NOT_AUTO_APPROVED), fake_verdict_info)
     call_command('auto_approve')
     assert approve_mock.call_count == 0
     assert create_summary_for_version_mock.call_args == ((
         self.version, ), {
             'max_average_daily_users':
             10000,
             'min_approved_updates':
             1,
             'dry_run':
             False,
             'post_review':
             False
         })
     assert get_reviewing_cache(self.addon.pk) is None
     self._check_stats({
         'total': 1,
         'uses_custom_csp': 1,
         'uses_native_messaging': 1,
         'uses_content_script_for_all_urls': 1,
         'too_many_average_daily_users': 1,
         'too_few_approved_updates': 1,
     })
コード例 #10
0
 def test_verdict_info_pretty(self):
     summary = AutoApprovalSummary.objects.create(
         version=self.version,
         uses_custom_csp=True,
         uses_native_messaging=True,
         uses_content_script_for_all_urls=True,
         average_daily_users=self.addon.average_daily_users,
         approved_updates=333)
     expected_result = list(
         AutoApprovalSummary.verdict_info_prettifier({
             'too_few_approved_updates':
             True,
             'too_many_average_daily_users':
             True,
             'uses_content_script_for_all_urls':
             True,
             'uses_custom_csp':
             True,
             'uses_native_messaging':
             True
         }))
     result = list(
         summary.calculate_verdict(
             max_average_daily_users=summary.average_daily_users - 1,
             min_approved_updates=summary.approved_updates + 1,
             pretty=True))
     assert result == expected_result
     assert summary.verdict == amo.NOT_AUTO_APPROVED
コード例 #11
0
ファイル: views.py プロジェクト: Ahmad-Shafique/addons-server
def queue_content_review(request):
    qs = (
        AutoApprovalSummary.get_content_review_queue()
        .select_related('addonapprovalscounter')
        .order_by('addonapprovalscounter__last_content_review', 'created')
    )
    return _queue(request, ContentReviewTable, 'content_review',
                  qs=qs, SearchForm=None)
コード例 #12
0
 def test_successful_verdict(self, create_summary_for_version_mock):
     create_summary_for_version_mock.return_value = (
         AutoApprovalSummary(verdict=amo.AUTO_APPROVED), {})
     call_command('auto_approve')
     assert create_summary_for_version_mock.call_args == (
         (self.version, ),
         {'max_average_daily_users': 10000, 'min_approved_updates': 1,
          'dry_run': False})
     assert get_reviewing_cache(self.addon.pk) is None
     self._check_stats({'total': 1, 'auto_approved': 1})
コード例 #13
0
 def test_no_locking_if_already_locked(
         self, create_summary_for_version_mock, check_is_locked_mock,
         clear_reviewing_cache_mock, set_reviewing_cache_mock):
     check_is_locked_mock.return_value = True
     create_summary_for_version_mock.return_value = (
         AutoApprovalSummary(), {})
     call_command('auto_approve')
     assert create_summary_for_version_mock.call_count == 1
     assert set_reviewing_cache_mock.call_count == 0
     assert clear_reviewing_cache_mock.call_count == 0
コード例 #14
0
 def test_create_summary_no_previously_approved_versions(
         self, calculate_verdict_mock):
     AddonApprovalsCounter.objects.all().delete()
     self.version.reload()
     calculate_verdict_mock.return_value = {'dummy_verdict': True}
     summary, info = AutoApprovalSummary.create_summary_for_version(
         self.version,
         max_average_daily_users=111, min_approved_updates=222)
     assert summary.pk
     assert summary.approved_updates == 0
     assert info == {'dummy_verdict': True}
コード例 #15
0
def queue_auto_approved(request):
    qs = (AutoApprovalSummary.get_auto_approved_queue().select_related(
        'addonapprovalscounter',
        '_current_version__autoapprovalsummary').order_by(
            '-_current_version__autoapprovalsummary__weight',
            'addonapprovalscounter__last_human_review', 'created'))
    return _queue(request,
                  AutoApprovedTable,
                  'auto_approved',
                  qs=qs,
                  SearchForm=None)
コード例 #16
0
def queue_counts(type=None,
                 unlisted=False,
                 admin_reviewer=False,
                 limited_reviewer=False,
                 **kw):
    def construct_query(query_type, days_min=None, days_max=None):
        query = query_type.objects

        if not admin_reviewer:
            query = exclude_admin_only_addons(query)
        if days_min:
            query = query.having('waiting_time_days >=', days_min)
        if days_max:
            query = query.having('waiting_time_days <=', days_max)
        if limited_reviewer:
            query = query.having('waiting_time_hours >=',
                                 amo.REVIEW_LIMITED_DELAY_HOURS)

        return query.count

    counts = {
        'pending': construct_query(ViewPendingQueue, **kw),
        'nominated': construct_query(ViewFullReviewQueue, **kw),
        'moderated': Review.objects.all().to_moderate().count,
        'auto_approved': (AutoApprovalSummary.get_auto_approved_queue().count),
        'content_review':
        (AutoApprovalSummary.get_content_review_queue().count),
    }
    if unlisted:
        counts = {
            'all':
            (ViewUnlistedAllList.objects if admin_reviewer else
             exclude_admin_only_addons(ViewUnlistedAllList.objects)).count
        }
    rv = {}
    if isinstance(type, basestring):
        return counts[type]()
    for k, v in counts.items():
        if not isinstance(type, list) or k in type:
            rv[k] = v()
    return rv
コード例 #17
0
 def test_locking(self, create_summary_for_version_mock,
                  clear_reviewing_cache_mock, set_reviewing_cache_mock):
     create_summary_for_version_mock.return_value = (AutoApprovalSummary(),
                                                     {})
     call_command('auto_approve')
     assert create_summary_for_version_mock.call_count == 1
     assert set_reviewing_cache_mock.call_count == 1
     assert set_reviewing_cache_mock.call_args == ((self.addon.pk,
                                                    settings.TASK_USER_ID),
                                                   {})
     assert clear_reviewing_cache_mock.call_count == 1
     assert clear_reviewing_cache_mock.call_args == ((self.addon.pk, ), {})
コード例 #18
0
 def test_successful_verdict_dry_run(self, create_summary_for_version_mock,
                                     approve_mock):
     create_summary_for_version_mock.return_value = (AutoApprovalSummary(
         verdict=amo.WOULD_HAVE_BEEN_AUTO_APPROVED), {})
     call_command('auto_approve', '--dry-run')
     assert approve_mock.call_count == 0
     assert create_summary_for_version_mock.call_args == ((self.version, ),
                                                          {
                                                              'dry_run':
                                                              True
                                                          })
     assert get_reviewing_cache(self.addon.pk) is None
     self._check_stats({'total': 1, 'auto_approved': 1})
コード例 #19
0
 def test_failed_verdict(self, create_summary_for_version_mock,
                         approve_mock):
     fake_verdict_info = {'is_locked': True}
     create_summary_for_version_mock.return_value = (AutoApprovalSummary(
         verdict=amo.NOT_AUTO_APPROVED), fake_verdict_info)
     call_command('auto_approve')
     assert approve_mock.call_count == 0
     assert create_summary_for_version_mock.call_args == ((self.version, ),
                                                          {
                                                              'dry_run':
                                                              False
                                                          })
     assert get_reviewing_cache(self.addon.pk) is None
     self._check_stats({
         'total': 1,
         'is_locked': 1,
     })
コード例 #20
0
    def test_create_summary_already_existing(self):
        # Create a dummy summary manually, then call the method to create a
        # real one. It should have just updated the previous instance.
        summary = AutoApprovalSummary.objects.create(
            version=self.version,
            uses_custom_csp=True,
            uses_native_messaging=True,
            uses_content_script_for_all_urls=True)
        assert summary.pk
        assert summary.version == self.version
        assert summary.uses_custom_csp is True
        assert summary.uses_native_messaging is True
        assert summary.uses_content_script_for_all_urls is True
        assert summary.average_daily_users == 0
        assert summary.approved_updates == 0
        assert summary.verdict == amo.NOT_AUTO_APPROVED

        previous_summary_pk = summary.pk

        summary, info = AutoApprovalSummary.create_summary_for_version(
            self.version,
            max_average_daily_users=self.addon.average_daily_users + 1,
            min_approved_updates=1)

        assert summary.pk == previous_summary_pk
        assert summary.version == self.version
        assert summary.uses_custom_csp is False
        assert summary.uses_native_messaging is False
        assert summary.uses_content_script_for_all_urls is False
        assert summary.average_daily_users == self.addon.average_daily_users
        assert summary.approved_updates == 1
        assert summary.verdict == amo.AUTO_APPROVED
        assert info == {
            'too_few_approved_updates': False,
            'too_many_average_daily_users': False,
            'uses_content_script_for_all_urls': False,
            'uses_custom_csp': False,
            'uses_native_messaging': False,
            'has_info_request': False,
            'is_locked': False,
            'is_under_admin_review': False,
        }
コード例 #21
0
 def test_create_summary_for_version(self, calculate_verdict_mock):
     calculate_verdict_mock.return_value = {'dummy_verdict': True}
     summary, info = AutoApprovalSummary.create_summary_for_version(
         self.version,
         max_average_daily_users=111, min_approved_updates=222)
     assert calculate_verdict_mock.call_count == 1
     assert calculate_verdict_mock.call_args == ({
         'max_average_daily_users': 111,
         'min_approved_updates': 222,
         'dry_run': False
     },)
     assert summary.pk
     assert summary.version == self.version
     assert summary.uses_custom_csp is False
     assert summary.uses_native_messaging is False
     assert summary.uses_content_script_for_all_urls is False
     assert summary.average_daily_users == self.addon.average_daily_users
     assert (summary.approved_updates ==
             self.addon.addonapprovalscounter.counter)
     assert info == {'dummy_verdict': True}
コード例 #22
0
 def test_create_summary_no_files(self):
     self.file.delete()
     del self.version.all_files
     with self.assertRaises(AutoApprovalNotEnoughFilesError):
         AutoApprovalSummary.create_summary_for_version(self.version)
コード例 #23
0
    def handle(self, *args, **options):
        dry_run = options.get('dry_run', False)
        max_average_daily_users = int(
            get_config('AUTO_APPROVAL_MAX_AVERAGE_DAILY_USERS') or 0)
        min_approved_updates = int(
            get_config('AUTO_APPROVAL_MIN_APPROVED_UPDATES') or 0)

        if min_approved_updates <= 0 or max_average_daily_users <= 0:
            # Auto approval are shut down if one of those values is not present
            # or <= 0.
            url = '%s%s' % (settings.SITE_URL,
                            reverse('admin:zadmin_config_changelist'))
            raise CommandError(
                'Auto-approvals are deactivated because either '
                'AUTO_APPROVAL_MAX_AVERAGE_DAILY_USERS or '
                'AUTO_APPROVAL_MIN_APPROVED_UPDATES have not been '
                'set or were set to 0. Use the admin tools Config model to '
                'set them by going to %s.' % url)

        stats = Counter()
        qs = self.fetch_candidates()
        stats['total'] = len(qs)

        successful_verdict = (amo.WOULD_HAVE_BEEN_AUTO_APPROVED
                              if dry_run else amo.AUTO_APPROVED)

        for version in qs:
            # Is the addon already locked by a reviewer ?
            if get_reviewing_cache(version.addon.pk):
                stats['locked'] += 1
                continue

            # If admin review or more information was requested, skip this
            # version, let a human handle it.
            if version.addon.admin_review or version.has_info_request:
                stats['flagged'] += 1
                continue

            # Lock the addon for ourselves, no reviewer should touch it.
            set_reviewing_cache(version.addon.pk, settings.TASK_USER_ID)

            try:
                log.info('Processing %s version %s...',
                         unicode(version.addon.name), unicode(version.version))
                summary, info = AutoApprovalSummary.create_summary_for_version(
                    version,
                    max_average_daily_users=max_average_daily_users,
                    min_approved_updates=min_approved_updates,
                    dry_run=dry_run)
                log.info('Auto Approval for %s version %s: %s',
                         unicode(version.addon.name), unicode(version.version),
                         summary.get_verdict_display())
                stats.update({k: int(v) for k, v in info.items()})
                if summary.verdict == successful_verdict:
                    stats['auto_approved'] += 1
                # FIXME: implement auto-approve if verdict is amo.AUTO_APPROVED

            except (AutoApprovalNotEnoughFilesError,
                    AutoApprovalNoValidationResultError):
                log.info(
                    'Version %s was skipped either because it had no '
                    'file or because it had no validation attached.', version)
                stats['error'] += 1
            finally:
                clear_reviewing_cache(version.addon.pk)

        self.log_final_summary(stats, dry_run=dry_run)
コード例 #24
0
    def test_check_has_info_request(self):
        assert AutoApprovalSummary.check_has_info_request(
            self.version) is False

        self.version.update(has_info_request=True)
        assert AutoApprovalSummary.check_has_info_request(self.version) is True