Remove views/code about info requests (#15168)

* Remove views/code about info requests

Info requests are no longer possible, replaced with delayed rejections
(or simple reviewer reply with no deadline).

* Move migration

* Remove `request` from VersionForm, it's no longer needed
This commit is contained in:
Mathieu Pillard 2020-08-05 14:29:34 +02:00 коммит произвёл GitHub
Родитель 8df81b9be4
Коммит 66348f6b01
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
29 изменённых файлов: 89 добавлений и 789 удалений

Просмотреть файл

@ -85,7 +85,6 @@ add-on.
:>json boolean needs_admin_code_review: Boolean indicating whether the add-on needs its code to be reviewed by an admin or not.
:>json boolean needs_admin_content_review: Boolean indicating whether the add-on needs its content to be reviewed by an admin or not.
:>json boolean needs_admin_theme_review: Boolean indicating whether the theme needs to be reviewed by an admin or not.
:>json string|null pending_info_request: Deadline date for the pending info request as a string, or ``null``.
------------------
Allow resubmission

Просмотреть файл

@ -9,7 +9,7 @@ Hello,
*********
To respond, please reply to this email or visit {{ url }}. {% if is_info_request and number_of_days_left %}If we do not hear from you within {{ number_of_days_left }} of this notification, this listing may be removed from addons.mozilla.org.{% endif %}
To respond, please reply to this email or visit {{ url }}.
Thank you for your attention.

Просмотреть файл

@ -3,7 +3,6 @@ import copy
import json
import os
from datetime import datetime, timedelta
from email.utils import formataddr
from django.conf import settings
@ -23,7 +22,6 @@ from olympia.activity.utils import (
ActivityEmailTokenError, ActivityEmailUUIDError, add_email_to_activity_log,
add_email_to_activity_log_wrapper, log_and_notify,
notify_about_activity_log, NOTIFICATIONS_FROM_EMAIL, send_activity_mail)
from olympia.addons.models import Addon, AddonReviewerFlags
from olympia.amo.templatetags.jinja_helpers import absolutify
from olympia.amo.tests import TestCase, addon_factory, user_factory
from olympia.amo.urlresolvers import reverse
@ -280,21 +278,6 @@ class TestLogAndNotify(TestCase):
assert reply_to.endswith(settings.INBOUND_EMAIL_DOMAIN)
return recipients
def _check_email_info_request(self, call, url, reason_text, days_text):
subject = call[0][0]
body = call[0][1]
assert subject == u'Mozilla Add-ons: Action Required for %s %s' % (
self.addon.name, self.version.version)
assert ('visit %s' % url) in body
assert ('receiving this email because %s' % reason_text) in body
if days_text is not None:
assert 'If we do not hear from you within' in body
assert days_text in body
assert 'reviewing version %s of the add-on %s' % (
self.version.version, self.addon.name) in body
assert self.reviewer.name not in body
assert self.reviewer.reviewer_name in body
def _check_email(self, call, url, reason_text):
subject = call[0][0]
body = call[0][1]
@ -305,118 +288,8 @@ class TestLogAndNotify(TestCase):
assert 'If we do not hear from you within' not in body
assert self.reviewer.name not in body
@mock.patch('olympia.activity.utils.send_mail')
def test_reviewer_request_for_information(self, send_mail_mock):
AddonReviewerFlags.objects.create(
addon=self.addon,
pending_info_request=datetime.now() + timedelta(days=14))
self._create(amo.LOG.REQUEST_INFORMATION, self.reviewer)
log_and_notify(
amo.LOG.REQUEST_INFORMATION, 'blah', self.reviewer, self.version)
assert send_mail_mock.call_count == 2 # Both authors.
sender = formataddr(
(self.reviewer.reviewer_name, NOTIFICATIONS_FROM_EMAIL))
assert sender == send_mail_mock.call_args_list[0][1]['from_email']
recipients = self._recipients(send_mail_mock)
assert len(recipients) == 2
assert self.developer.email in recipients
assert self.developer2.email in recipients
# The reviewer who sent it doesn't get their email back.
assert self.reviewer.email not in recipients
self._check_email_info_request(
send_mail_mock.call_args_list[0],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
'14 days of this notification')
self._check_email_info_request(
send_mail_mock.call_args_list[1],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
'14 days of this notification')
@mock.patch('olympia.activity.utils.send_mail')
def test_reviewer_request_for_information_close_date(self, send_mail_mock):
AddonReviewerFlags.objects.create(
addon=self.addon,
pending_info_request=datetime.now() + timedelta(days=1))
self._create(amo.LOG.REQUEST_INFORMATION, self.reviewer)
log_and_notify(
amo.LOG.REQUEST_INFORMATION, 'blah', self.reviewer, self.version)
assert send_mail_mock.call_count == 2 # Both authors.
sender = formataddr(
(self.reviewer.reviewer_name, NOTIFICATIONS_FROM_EMAIL))
assert sender == send_mail_mock.call_args_list[0][1]['from_email']
recipients = self._recipients(send_mail_mock)
assert len(recipients) == 2
assert self.developer.email in recipients
assert self.developer2.email in recipients
# The reviewer who sent it doesn't get their email back.
assert self.reviewer.email not in recipients
self._check_email_info_request(
send_mail_mock.call_args_list[0],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
'one (1) day of this notification')
self._check_email_info_request(
send_mail_mock.call_args_list[1],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
'one (1) day of this notification')
@mock.patch('olympia.activity.utils.send_mail')
def test_reviewer_request_for_information_far_date(self, send_mail_mock):
AddonReviewerFlags.objects.create(
addon=self.addon,
pending_info_request=datetime.now() + timedelta(days=21))
self._create(amo.LOG.REQUEST_INFORMATION, self.reviewer)
log_and_notify(
amo.LOG.REQUEST_INFORMATION, 'blah', self.reviewer, self.version)
assert send_mail_mock.call_count == 2 # Both authors.
sender = formataddr(
(self.reviewer.reviewer_name, NOTIFICATIONS_FROM_EMAIL))
assert sender == send_mail_mock.call_args_list[0][1]['from_email']
recipients = self._recipients(send_mail_mock)
assert len(recipients) == 2
assert self.developer.email in recipients
assert self.developer2.email in recipients
# The reviewer who sent it doesn't get their email back.
assert self.reviewer.email not in recipients
self._check_email_info_request(
send_mail_mock.call_args_list[0],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
'21 days of this notification')
self._check_email_info_request(
send_mail_mock.call_args_list[1],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
'21 days of this notification')
def test_post_reviewer_request_for_information(self):
GroupUser.objects.filter(user=self.reviewer).delete()
self.grant_permission(
self.reviewer, 'Addons:PostReview', 'Reviewers: Foo')
self.test_reviewer_request_for_information()
def test_content_reviewer_request_for_information(self):
GroupUser.objects.filter(user=self.reviewer).delete()
self.grant_permission(
self.reviewer, 'Addons:ContentReview', 'Reviewers: Bar')
self.test_reviewer_request_for_information()
@mock.patch('olympia.activity.utils.send_mail')
def test_developer_reply(self, send_mail_mock):
# Set pending info request flag to make sure
# it has been dropped after the reply.
AddonReviewerFlags.objects.create(
addon=self.addon,
pending_info_request=datetime.now() + timedelta(days=1))
# One from the reviewer.
self._create(amo.LOG.REJECT_VERSION, self.reviewer)
# One from the developer. So the developer is on the 'thread'
@ -453,9 +326,6 @@ class TestLogAndNotify(TestCase):
send_mail_mock.call_args_list[1],
review_url, 'you reviewed this add-on.')
self.addon = Addon.objects.get(pk=self.addon.pk)
assert not self.addon.pending_info_request
@mock.patch('olympia.activity.utils.send_mail')
def test_reviewer_reply(self, send_mail_mock):
# One from the reviewer.
@ -549,40 +419,6 @@ class TestLogAndNotify(TestCase):
review_url,
'you are member of the activity email cc group.')
@mock.patch('olympia.activity.utils.send_mail')
def test_mail_needinfo_correct_subject(self, send_mail_mock):
self.grant_permission(self.reviewer, 'None:None', ACTIVITY_MAIL_GROUP)
action = amo.LOG.REQUEST_INFORMATION
comments = u'Thïs is á reply'
log_and_notify(action, comments, self.developer, self.version)
logs = ActivityLog.objects.filter(action=action.id)
assert len(logs) == 1
recipients = self._recipients(send_mail_mock)
sender = formataddr(
(self.developer.name, NOTIFICATIONS_FROM_EMAIL))
assert sender == send_mail_mock.call_args_list[0][1]['from_email']
developer_subject = send_mail_mock.call_args_list[0][0][0]
assert developer_subject == (
u'Mozilla Add-ons: Action Required for '
'%s %s' % (self.addon.name, self.version.version))
reviewer_subject = send_mail_mock.call_args_list[1][0][0]
assert reviewer_subject == u'Mozilla Add-ons: %s %s' % (
self.addon.name, self.version.version)
assert len(recipients) == 2
# self.reviewers wasn't on the thread, but gets an email anyway.
assert self.reviewer.email in recipients
assert self.developer2.email in recipients
review_url = absolutify(
reverse('reviewers.review',
kwargs={'addon_id': self.version.addon.pk,
'channel': 'listed'},
add_prefix=False))
self._check_email(send_mail_mock.call_args_list[1],
review_url,
'you are member of the activity email cc group.')
@mock.patch('olympia.activity.utils.send_mail')
def test_task_user_doesnt_get_mail(self, send_mail_mock):
"""The task user account is used to auto-sign unlisted addons, amongst
@ -717,7 +553,7 @@ class TestLogAndNotify(TestCase):
@mock.patch('olympia.activity.utils.send_mail')
def test_notify_about_previous_activity(self, send_mail_mock):
# Create an activity to use when notifying.
activity = self._create(amo.LOG.REQUEST_INFORMATION, self.reviewer)
activity = self._create(amo.LOG.REVIEWER_REPLY_VERSION, self.reviewer)
notify_about_activity_log(self.addon, self.version, activity)
assert ActivityLog.objects.count() == 1 # No new activity created.
@ -732,16 +568,14 @@ class TestLogAndNotify(TestCase):
# The reviewer who sent it doesn't get their email back.
assert self.reviewer.email not in recipients
self._check_email_info_request(
self._check_email(
send_mail_mock.call_args_list[0],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
days_text=None)
self._check_email_info_request(
'you are listed as an author of this add-on.')
self._check_email(
send_mail_mock.call_args_list[1],
absolutify(self.addon.get_dev_url('versions')),
'you are listed as an author of this add-on.',
days_text=None)
'you are listed as an author of this add-on.')
@pytest.mark.django_db

Просмотреть файл

@ -148,7 +148,7 @@ class TestReviewNotesViewSetDetail(ReviewNotesViewSetDetailMixin, TestCase):
self.user = user_factory()
self.version = self.addon.find_latest_version(
channel=amo.RELEASE_CHANNEL_LISTED)
self.note = self.log(u'noôo!', amo.LOG.REQUEST_INFORMATION,
self.note = self.log(u'noôo!', amo.LOG.REVIEWER_REPLY_VERSION,
self.days_ago(0))
self._set_tested_url()
@ -157,7 +157,7 @@ class TestReviewNotesViewSetDetail(ReviewNotesViewSetDetailMixin, TestCase):
assert response.status_code == 200
result = json.loads(response.content)
assert result['id'] == self.note.pk
assert result['action_label'] == amo.LOG.REQUEST_INFORMATION.short
assert result['action_label'] == amo.LOG.REVIEWER_REPLY_VERSION.short
assert result['comments'] == u'noôo!'
assert result['highlight'] # Its the first reply so highlight

Просмотреть файл

@ -1,12 +1,11 @@
import re
from datetime import datetime, timedelta
from datetime import datetime
from email.utils import formataddr
from html import unescape
from django.conf import settings
from django.forms import ValidationError
from django.contrib.humanize.templatetags.humanize import apnumber
from django.template import loader
from django.utils import translation
@ -19,7 +18,6 @@ import olympia.core.logger
from olympia import amo
from olympia.access import acl
from olympia.activity.models import ActivityLog, ActivityLogToken
from olympia.addons.models import AddonReviewerFlags
from olympia.amo.templatetags.jinja_helpers import absolutify
from olympia.amo.urlresolvers import reverse
from olympia.amo.utils import send_mail
@ -220,14 +218,6 @@ def log_and_notify(action, comments, note_creator, version, perm_setting=None,
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
@ -256,36 +246,12 @@ def notify_about_activity_log(addon, version, note, perm_setting=None,
'url': absolutify(addon.get_dev_url('versions')),
'SITE_URL': settings.SITE_URL,
'email_reason': 'you are listed as an author of this add-on',
'is_info_request': note.action == amo.LOG.REQUEST_INFORMATION.id,
}
# Not being localised because we don't know the recipients locale.
with translation.override('en-US'):
if note.action == amo.LOG.REQUEST_INFORMATION.id:
if addon.pending_info_request:
days_left = (
# We pad the time left with an extra hour so that the email
# does not end up saying "6 days left" because a few
# seconds or minutes passed between the datetime was saved
# and the email was sent.
addon.pending_info_request + timedelta(hours=1) -
datetime.now()
).days
if days_left > 9:
author_context_dict['number_of_days_left'] = (
'%d days' % days_left)
elif days_left > 1:
author_context_dict['number_of_days_left'] = (
'%s (%d) days' % (apnumber(days_left), days_left))
else:
author_context_dict['number_of_days_left'] = 'one (1) day'
subject = u'Mozilla Add-ons: Action Required for %s %s' % (
addon.name, version.version)
reviewer_subject = u'Mozilla Add-ons: %s %s' % (
addon.name, version.version)
else:
subject = reviewer_subject = u'Mozilla Add-ons: %s %s' % (
addon.name, version.version)
subject = reviewer_subject = u'Mozilla Add-ons: %s %s' % (
addon.name, version.version)
# Build and send the mail for authors.
template = template_from_user(note.user, version)
from_email = formataddr((note.author_name, NOTIFICATIONS_FROM_EMAIL))

Просмотреть файл

@ -0,0 +1,18 @@
# Generated by Django 2.2.14 on 2020-08-03 13:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('addons', '0017_addonreviewerflags_notified_about_expiring_delayed_rejections'),
]
operations = [
migrations.AlterField(
model_name='addonreviewerflags',
name='notified_about_expiring_info_request',
field=models.NullBooleanField(default=None),
),
]

Просмотреть файл

@ -1497,18 +1497,6 @@ class Addon(OnChangeMixin, ModelBase):
except AddonReviewerFlags.DoesNotExist:
return None
@property
def pending_info_request(self):
try:
return self.reviewerflags.pending_info_request
except AddonReviewerFlags.DoesNotExist:
return None
@property
def expired_info_request(self):
info_request = self.pending_info_request
return info_request and info_request < datetime.now()
@property
def auto_approval_delayed_indefinitely(self):
return self.auto_approval_delayed_until == datetime.max
@ -1733,8 +1721,6 @@ class AddonReviewerFlags(ModelBase):
default=None)
auto_approval_delayed_until = models.DateTimeField(
default=None, null=True)
pending_info_request = models.DateTimeField(default=None, null=True)
notified_about_expiring_info_request = models.BooleanField(default=False)
notified_about_auto_approval_delay = models.NullBooleanField(default=None)
notified_about_expiring_delayed_rejections = models.NullBooleanField(
default=None)

Просмотреть файл

@ -1506,37 +1506,6 @@ class TestAddonModels(TestCase):
flags.update(needs_admin_theme_review=True)
assert addon.needs_admin_theme_review is True
def test_pending_info_request_property(self):
addon = Addon.objects.get(pk=3615)
# No flags: None
assert addon.pending_info_request is None
# Flag present, value is None (default): None.
flags = AddonReviewerFlags.objects.create(addon=addon)
assert flags.pending_info_request is None
assert addon.pending_info_request is None
# Flag present, value is a date.
in_the_past = self.days_ago(1)
flags.update(pending_info_request=in_the_past)
assert addon.pending_info_request == in_the_past
def test_expired_info_request_property(self):
addon = Addon.objects.get(pk=3615)
# No flags: None
assert addon.expired_info_request is None
# Flag present, value is None (default): None.
flags = AddonReviewerFlags.objects.create(addon=addon)
assert flags.pending_info_request is None
assert addon.expired_info_request is None
# Flag present, value is a date in the past.
in_the_past = self.days_ago(1)
flags.update(pending_info_request=in_the_past)
assert addon.expired_info_request
# Flag present, value is a date in the future.
in_the_future = datetime.now() + timedelta(days=2)
flags.update(pending_info_request=in_the_future)
assert not addon.expired_info_request
def test_reset_notified_about_auto_approval_delay(self):
addon = Addon.objects.get(pk=3615)
assert not AddonReviewerFlags.objects.filter(addon=addon).exists()

Просмотреть файл

@ -186,6 +186,7 @@ class REQUEST_VERSION(_LOG):
review_queue = True
# Obsolete now that we have pending rejections, kept for compatibility.
class REQUEST_INFORMATION(_LOG):
id = 44
format = _(u'{addon} {version} more information requested.')

Просмотреть файл

@ -25,10 +25,9 @@ from rest_framework.exceptions import Throttled
from olympia import amo
from olympia.access import acl
from olympia.activity.models import ActivityLog
from olympia.activity.utils import log_and_notify
from olympia.addons import tasks as addons_tasks
from olympia.addons.models import (
Addon, AddonApprovalsCounter, AddonCategory, AddonReviewerFlags, AddonUser,
Addon, AddonApprovalsCounter, AddonCategory, AddonUser,
AddonUserPendingConfirmation, Category, DeniedSlug, Preview)
from olympia.addons.utils import verify_mozilla_trademark
from olympia.amo.fields import HttpHttpsOnlyURLField, ReCaptchaField
@ -788,39 +787,10 @@ class VersionForm(WithSourceMixin, forms.ModelForm):
approval_notes = forms.CharField(
widget=TranslationTextarea(attrs={'rows': 4}), required=False)
source = forms.FileField(required=False, widget=SourceFileInput)
clear_pending_info_request = forms.BooleanField(required=False)
class Meta:
model = Version
fields = ('release_notes', 'clear_pending_info_request',
'approval_notes', 'source',)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(VersionForm, self).__init__(*args, **kwargs)
# Fetch latest reviewer comment if the addon has a pending info
# request, so that the template in which the form is used can display
# that comment.
if self.instance and self.instance.addon.pending_info_request:
try:
self.pending_info_request_comment = (
ActivityLog.objects.for_addons(self.instance.addon)
.filter(action=amo.LOG.REQUEST_INFORMATION.id)
.latest('pk')).details['comments']
except (ActivityLog.DoesNotExist, KeyError):
self.pending_info_request_comment = ''
def save(self, *args, **kwargs):
super(VersionForm, self).save(*args, **kwargs)
# Clear pending info request on the addon if requested, adding an entry
# in the Activity Log to indicate that.
if self.cleaned_data.get('clear_pending_info_request'):
AddonReviewerFlags.objects.update_or_create(
addon=self.instance.addon,
defaults={'pending_info_request': None})
log_and_notify(
amo.LOG.DEVELOPER_CLEAR_INFO_REQUEST, None,
self.request.user, self.instance)
fields = ('release_notes', 'approval_notes', 'source',)
class AppVersionChoiceField(forms.ModelChoiceField):

Просмотреть файл

@ -35,7 +35,6 @@
{{ reviewer_form.approval_notes }}
<p>{{ _('These notes will only be visible to you and our reviewers.') }}</p>
</div>
{% include "devhub/includes/clear_pending_info_request.html" %}
<div class="submission-buttons addon-submission-field">
<button type="submit">
{{ _('Submit Version') }}

Просмотреть файл

@ -1,8 +0,0 @@
{% if addon.pending_info_request %}
<div class="addon-submission-field clear-info-request">
<strong>{{ _('Pending information request:') }}</strong>
<blockquote><p> {{ reviewer_form.pending_info_request_comment }} </p></blockquote>
{{ reviewer_form.clear_pending_info_request }} <label for="{{ reviewer_form.clear_pending_info_request.auto_id }}">
{{ _('This request for information has been resolved') }}</label>
</div>
{% endif %}

Просмотреть файл

@ -113,9 +113,6 @@
<td>
{{ field.errors }}
{{ field }}
{% with reviewer_form = version_form %}
{% include "devhub/includes/clear_pending_info_request.html" %}
{% endwith %}
</td>
{% endwith %}
</tr>

Просмотреть файл

@ -128,28 +128,24 @@ class TestDevFilesStatus(TestCase):
@pytest.mark.parametrize(
'action1,action2,action3,expected_count', (
(LOG.REQUEST_INFORMATION, LOG.REQUEST_INFORMATION,
LOG.REQUEST_INFORMATION, 3),
# Tests with Developer_Reply
(LOG.DEVELOPER_REPLY_VERSION, LOG.REQUEST_INFORMATION,
LOG.REQUEST_INFORMATION, 2),
(LOG.REQUEST_INFORMATION, LOG.DEVELOPER_REPLY_VERSION,
LOG.REQUEST_INFORMATION, 1),
(LOG.REQUEST_INFORMATION, LOG.REQUEST_INFORMATION,
(LOG.REVIEWER_REPLY_VERSION, LOG.DEVELOPER_REPLY_VERSION,
LOG.REVIEWER_REPLY_VERSION, 1),
(LOG.REVIEWER_REPLY_VERSION, LOG.REVIEWER_REPLY_VERSION,
LOG.DEVELOPER_REPLY_VERSION, 0),
# Tests with Approval
(LOG.APPROVE_VERSION, LOG.REQUEST_INFORMATION,
LOG.REQUEST_INFORMATION, 2),
(LOG.REQUEST_INFORMATION, LOG.APPROVE_VERSION,
LOG.REQUEST_INFORMATION, 1),
(LOG.REQUEST_INFORMATION, LOG.REQUEST_INFORMATION,
(LOG.APPROVE_VERSION, LOG.REVIEWER_REPLY_VERSION,
LOG.REVIEWER_REPLY_VERSION, 2),
(LOG.REVIEWER_REPLY_VERSION, LOG.APPROVE_VERSION,
LOG.REVIEWER_REPLY_VERSION, 1),
(LOG.REVIEWER_REPLY_VERSION, LOG.REVIEWER_REPLY_VERSION,
LOG.APPROVE_VERSION, 0),
# Tests with Rejection
(LOG.REJECT_VERSION, LOG.REQUEST_INFORMATION,
LOG.REQUEST_INFORMATION, 2),
(LOG.REQUEST_INFORMATION, LOG.REJECT_VERSION,
LOG.REQUEST_INFORMATION, 1),
(LOG.REQUEST_INFORMATION, LOG.REQUEST_INFORMATION,
(LOG.REJECT_VERSION, LOG.REVIEWER_REPLY_VERSION,
LOG.REVIEWER_REPLY_VERSION, 2),
(LOG.REVIEWER_REPLY_VERSION, LOG.REJECT_VERSION,
LOG.REVIEWER_REPLY_VERSION, 1),
(LOG.REVIEWER_REPLY_VERSION, LOG.REVIEWER_REPLY_VERSION,
LOG.REJECT_VERSION, 0),
)
)

Просмотреть файл

@ -23,7 +23,7 @@ from waffle.testutils import override_switch
from olympia import amo
from olympia.activity.models import ActivityLog
from olympia.addons.models import (
Addon, AddonCategory, AddonReviewerFlags, Category)
Addon, AddonCategory, Category)
from olympia.amo.tests import (
TestCase, addon_factory, create_default_webext_appversion, formset,
initial, user_factory, version_factory)
@ -2361,60 +2361,6 @@ class TestVersionSubmitDetails(TestSubmitBase):
response, reverse('devhub.submit.version.finish',
args=[self.addon.slug, self.version.pk]))
def test_show_request_for_information(self):
AddonReviewerFlags.objects.create(
addon=self.addon, pending_info_request=self.days_ago(2))
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 b'this should not be shown' not in response.content
assert b'this is an info request' in response.content
def test_dont_show_request_for_information_if_none_pending(self):
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 b'this should not be shown' not in response.content
assert b'this is an info request' not in response.content
def test_clear_request_for_information(self):
AddonReviewerFlags.objects.create(
addon=self.addon, pending_info_request=self.days_ago(2))
response = self.client.post(
self.url, {'clear_pending_info_request': True})
self.assert3xx(
response, reverse('devhub.submit.version.finish',
args=[self.addon.slug, self.version.pk]))
flags = AddonReviewerFlags.objects.get(addon=self.addon)
assert flags.pending_info_request is None
activity = ActivityLog.objects.for_addons(self.addon).filter(
action=amo.LOG.DEVELOPER_CLEAR_INFO_REQUEST.id).get()
assert activity.user == self.user
assert activity.arguments == [self.addon, self.version]
def test_dont_clear_request_for_information(self):
past_date = self.days_ago(2)
AddonReviewerFlags.objects.create(
addon=self.addon, pending_info_request=past_date)
response = self.client.post(self.url)
self.assert3xx(
response, reverse('devhub.submit.version.finish',
args=[self.addon.slug, self.version.pk]))
flags = AddonReviewerFlags.objects.get(addon=self.addon)
assert flags.pending_info_request == past_date
assert not ActivityLog.objects.for_addons(self.addon).filter(
action=amo.LOG.DEVELOPER_CLEAR_INFO_REQUEST.id).exists()
def test_can_cancel_review(self):
addon = self.get_addon()
addon_status = addon.status

Просмотреть файл

@ -606,9 +606,9 @@ class TestVersion(TestCase):
def test_pending_activity_count(self):
v2, _ = self._extra_version_and_file(amo.STATUS_AWAITING_REVIEW)
# Add some activity log messages
ActivityLog.create(amo.LOG.REQUEST_INFORMATION, v2.addon, v2,
ActivityLog.create(amo.LOG.REVIEWER_REPLY_VERSION, v2.addon, v2,
user=self.user)
ActivityLog.create(amo.LOG.REQUEST_INFORMATION, v2.addon, v2,
ActivityLog.create(amo.LOG.REVIEWER_REPLY_VERSION, v2.addon, v2,
user=self.user)
response = self.client.get(self.url)
@ -830,52 +830,6 @@ class TestVersionEditDetails(TestVersionEditBase):
assert version.source
assert not version.addon.needs_admin_code_review
def test_show_request_for_information(self):
self.user = UserProfile.objects.latest('pk')
AddonReviewerFlags.objects.create(
addon=self.addon, pending_info_request=self.days_ago(2))
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 b'this should not be shown' not in response.content
assert b'this is an info request' in response.content
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 b'this should not be shown' not in response.content
assert b'this is an info request' not in response.content
def test_clear_request_for_information(self):
AddonReviewerFlags.objects.create(
addon=self.addon, pending_info_request=self.days_ago(2))
response = self.client.post(
self.url, self.formset(clear_pending_info_request=True))
assert response.status_code == 302
flags = AddonReviewerFlags.objects.get(addon=self.addon)
assert flags.pending_info_request is None
def test_dont_clear_request_for_information(self):
past_date = self.days_ago(2)
AddonReviewerFlags.objects.create(
addon=self.addon, pending_info_request=past_date)
response = self.client.post(self.url, self.formset())
assert response.status_code == 302
flags = AddonReviewerFlags.objects.get(addon=self.addon)
assert flags.pending_info_request == past_date
class TestVersionEditSearchEngine(TestVersionEditMixin, TestCase):
# https://bugzilla.mozilla.org/show_bug.cgi?id=605941

Просмотреть файл

@ -29,7 +29,6 @@ from olympia.access import acl
from olympia.accounts.utils import redirect_for_login, _is_safe_url
from olympia.accounts.views import API_TOKEN_COOKIE, logout_user
from olympia.activity.models import ActivityLog, VersionLog
from olympia.activity.utils import log_and_notify
from olympia.addons.models import (
Addon, AddonReviewerFlags, AddonUser, AddonUserPendingConfirmation)
from olympia.addons.views import BaseFilter
@ -1004,7 +1003,6 @@ def version_edit(request, addon_id, addon, version_id):
request.POST or None,
request.FILES or None,
instance=version,
request=request,
) if not static_theme else None
data = {}
@ -1038,31 +1036,19 @@ def version_edit(request, addon_id, addon, version_id):
_log_max_version_change(addon, version, form.instance)
if 'version_form' in data:
# VersionForm.save() clear the pending info request if the
# developer specifically asked for it, but we've got additional
# things to do here that depend on it.
had_pending_info_request = bool(addon.pending_info_request)
data['version_form'].save()
if 'approval_notes' in version_form.changed_data:
if had_pending_info_request:
log_and_notify(amo.LOG.APPROVAL_NOTES_CHANGED, None,
request.user, version)
else:
ActivityLog.create(amo.LOG.APPROVAL_NOTES_CHANGED,
addon, version, request.user)
ActivityLog.create(amo.LOG.APPROVAL_NOTES_CHANGED,
addon, version, request.user)
if ('source' in version_form.changed_data and
version_form.cleaned_data['source']):
AddonReviewerFlags.objects.update_or_create(
addon=addon, defaults={'needs_admin_code_review': True})
if had_pending_info_request:
log_and_notify(amo.LOG.SOURCE_CODE_UPLOADED, None,
request.user, version)
else:
ActivityLog.create(amo.LOG.SOURCE_CODE_UPLOADED,
addon, version, request.user)
ActivityLog.create(amo.LOG.SOURCE_CODE_UPLOADED,
addon, version, request.user)
messages.success(request, ugettext('Changes successfully saved.'))
return redirect('devhub.versions.edit', addon.slug, version_id)
@ -1522,7 +1508,7 @@ def _submit_details(request, addon, version):
if not static_theme:
# Static themes don't need this form
reviewer_form = forms.VersionForm(
post_data, instance=latest_version, request=request)
post_data, instance=latest_version)
context.update(reviewer_form=reviewer_form)
forms_list.append(reviewer_form)

Просмотреть файл

@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from django.core.management.base import BaseCommand
import olympia.core.logger
from olympia import amo
from olympia.activity.models import ActivityLog
from olympia.activity.utils import notify_about_activity_log
from olympia.addons.models import Addon
from olympia.users.notifications import reviewer_reviewed
log = olympia.core.logger.getLogger('z.reviewers.send_info_request')
class Command(BaseCommand):
help = 'Notify developers with pending info requests about to expire'
def handle(self, *args, **options):
# Fetch addons with request for information expiring in one day.
one_day_in_the_future = datetime.now() + timedelta(days=1)
qs = Addon.objects.filter(
reviewerflags__notified_about_expiring_info_request=False,
reviewerflags__pending_info_request__lt=one_day_in_the_future)
for addon in qs:
# The note we need to send the mail should always going to be the
# last information request, as making a new one extends the
# deadline.
note = ActivityLog.objects.for_addons(addon).filter(
action=amo.LOG.REQUEST_INFORMATION.id).latest('pk')
version = note.versionlog_set.latest('pk').version
log.info(
'Notifying developers of %s about expiring info request',
addon.pk)
# This re-sends the notification sent when the information was
# requested, but with the new delay in the body of the email now
# that the notification is about to expire.
notify_about_activity_log(
addon, version, note, perm_setting=reviewer_reviewed.short,
send_to_reviewers=False, send_to_staff=False)
addon.reviewerflags.update(
notified_about_expiring_info_request=True)

Просмотреть файл

@ -44,8 +44,6 @@ VIEW_QUEUE_FLAGS = (
('needs_admin_theme_review', 'needs-admin-theme-review',
_('Needs Admin Static Theme Review')),
('is_restart_required', 'is_restart_required', _('Requires Restart')),
('pending_info_request', 'info', _('More Information Requested')),
('expired_info_request', 'expired-info', _('Expired Information Request')),
('sources_provided', 'sources-provided', _('Sources provided')),
('is_webextension', 'webextension', _('WebExtension')),
('auto_approval_delayed_temporarily', 'auto-approval-delayed-temporarily',
@ -124,8 +122,6 @@ class ViewQueue(RawSQLModel):
source = models.CharField(max_length=100)
is_webextension = models.BooleanField()
latest_version = models.CharField(max_length=255)
pending_info_request = models.DateTimeField()
expired_info_request = models.NullBooleanField()
auto_approval_delayed_temporarily = models.NullBooleanField()
auto_approval_delayed_indefinitely = models.NullBooleanField()
waiting_time_days = models.IntegerField()
@ -149,11 +145,6 @@ class ViewQueue(RawSQLModel):
('needs_admin_theme_review',
'addons_addonreviewerflags.needs_admin_theme_review'),
('latest_version', 'versions.version'),
('pending_info_request',
'addons_addonreviewerflags.pending_info_request'),
('expired_info_request', (
'TIMEDIFF(addons_addonreviewerflags.pending_info_request,'
'NOW()) < 0')),
('auto_approval_delayed_temporarily', (
'TIMEDIFF(addons_addonreviewerflags.'
'auto_approval_delayed_until, NOW()) > 0 AND '

Просмотреть файл

@ -45,7 +45,6 @@ class AddonReviewerFlagsSerializer(serializers.ModelSerializer):
'needs_admin_code_review',
'needs_admin_content_review',
'needs_admin_theme_review',
'pending_info_request'
)

Просмотреть файл

@ -7,8 +7,6 @@
{{ _('Auto-approved Add-ons – Add-ons for Firefox') }}
{% elif tab == "moderated" %}
{{ _('Review Moderation – Add-ons for Firefox') }}
{% elif tab == "expired_info_requests" %}
{{ _('Expired Information Requests – Add-ons for Firefox') }}
{% elif tab == "unlisted_queue_all" %}
{{ _('Unlisted Add-ons – Add-ons for Firefox') }}
{% elif tab == "pending_rejection" %}

Просмотреть файл

@ -310,15 +310,6 @@
{% endif %}
{% endif %}
{% if addon.pending_info_request %}
<li>
<button data-api-url="{{ drf_url('reviewers-addon-flags', addon.pk) }}"
data-api-method="patch"
data-api-data="{&quot;pending_info_request&quot;: null}"
id="clear_pending_info_request" class="oneoff" type="button">{{ _('Clear information request') }}</button>
</li>
{% endif %}
{% if has_versions_pending_rejection %}
<li>
<button data-api-url="{{ drf_url('reviewers-addon-clear-pending-rejections', addon.pk) }}"

Просмотреть файл

@ -132,13 +132,6 @@ def queue_tabnav(context):
)
if acl.action_allowed(request, amo.permissions.REVIEWS_ADMIN):
tabnav.append(
('expired_info_requests', 'queue_expired_info_requests',
(ungettext('Expired Info Request ({0})',
'Expired Info Requests ({0})',
counts['expired_info_requests'])
.format(counts['expired_info_requests']))),
)
tabnav.append(
('pending_rejection', 'queue_pending_rejection',
(ungettext('Pending Rejection ({0})',

Просмотреть файл

@ -9,9 +9,7 @@ from django.core.management import call_command
from django.test.testcases import TransactionTestCase
from olympia import amo
from olympia.activity.models import ActivityLog
from olympia.activity.utils import ACTIVITY_MAIL_GROUP
from olympia.addons.models import (
AddonApprovalsCounter, AddonReviewerFlags, AddonUser)
from olympia.addons.models import AddonApprovalsCounter, AddonReviewerFlags
from olympia.amo.tests import (
TestCase, addon_factory, file_factory, user_factory, version_factory)
from olympia.amo.utils import days_ago
@ -673,68 +671,6 @@ class TestRecalculatePostReviewWeightsCommand(TestCase):
assert summary.modified != old_modified_date
class TestSendInfoRequestLastWarningNotification(TestCase):
@mock.patch('olympia.reviewers.management.commands.'
'send_info_request_last_warning_notifications.'
'notify_about_activity_log')
def test_non_expired(self, notify_about_activity_log_mock):
addon_factory() # Normal add-on, no pending info request.
addon_not_expired = addon_factory()
flags = AddonReviewerFlags.objects.create(
addon=addon_not_expired,
pending_info_request=datetime.now() + timedelta(days=1, hours=3))
call_command('send_info_request_last_warning_notifications')
assert notify_about_activity_log_mock.call_count == 0
assert flags.notified_about_expiring_info_request is False
@mock.patch('olympia.reviewers.management.commands.'
'send_info_request_last_warning_notifications.'
'notify_about_activity_log')
def test_already_notified(self, notify_about_activity_log_mock):
addon_factory()
addon_already_notified = addon_factory()
flags = AddonReviewerFlags.objects.create(
addon=addon_already_notified,
pending_info_request=datetime.now() + timedelta(hours=23),
notified_about_expiring_info_request=True)
call_command('send_info_request_last_warning_notifications')
assert notify_about_activity_log_mock.call_count == 0
assert flags.notified_about_expiring_info_request is True
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
class TestSendPendingRejectionLastWarningNotification(TestCase):
@classmethod
def setUpTestData(cls):

Просмотреть файл

@ -161,13 +161,6 @@ class TestExtensionQueueWithAwaitingReview(TestQueue):
assert queue.flags == [
('needs-admin-code-review', 'Needs Admin Code Review')]
def test_flags_info_request(self):
AddonReviewerFlags.objects.create(
addon=self.new_addon(),
pending_info_request=datetime.now() + timedelta(days=6))
queue = self.Queue.objects.get()
assert queue.flags == [('info', 'More Information Requested')]
def test_flags_is_restart_required(self):
self.new_addon().find_latest_version(self.channel).all_files[0].update(
is_restart_required=True)

Просмотреть файл

@ -411,13 +411,6 @@ class TestReviewLog(ReviewerTest):
assert pq(response.content)('#log-listing tr td').eq(1).text() == (
'Add-on has been deleted.')
def test_request_info_logs(self):
self.make_an_approval(amo.LOG.REQUEST_INFORMATION)
response = self.client.get(self.url)
assert response.status_code == 200
assert pq(response.content)('#log-listing tr td a').eq(1).text() == (
'More information requested')
def test_super_review_logs(self):
self.make_an_approval(amo.LOG.REQUEST_ADMIN_REVIEW_CODE)
response = self.client.get(self.url)
@ -610,53 +603,35 @@ class TestDashboard(TestCase):
admins_group = Group.objects.create(name='Admins', rules='*:*')
GroupUser.objects.create(user=self.user, group=admins_group)
# Pending addon with expired info request.
addon1 = addon_factory(name=u'Pending Addön 1',
status=amo.STATUS_NOMINATED)
AddonReviewerFlags.objects.create(
addon=addon1,
pending_info_request=self.days_ago(2))
# Pending addon
addon_factory(name='Pending Addön', status=amo.STATUS_NOMINATED)
# Public addon with expired info request.
addon2 = addon_factory(name=u'Public Addön 2',
status=amo.STATUS_APPROVED)
AddonReviewerFlags.objects.create(
addon=addon2,
pending_info_request=self.days_ago(42))
# Public addon
addon = addon_factory(name='Public Addön', status=amo.STATUS_APPROVED)
# Deleted addon with expired info request.
addon3 = addon_factory(name=u'Deleted Addön 3',
status=amo.STATUS_DELETED)
AddonReviewerFlags.objects.create(
addon=addon3,
pending_info_request=self.days_ago(42))
# Deleted addon
addon_factory(name='Deleted Addön', status=amo.STATUS_DELETED)
# Mozilla-disabled addon with expired info request.
addon4 = addon_factory(name=u'Disabled Addön 4',
status=amo.STATUS_DISABLED)
AddonReviewerFlags.objects.create(
addon=addon4,
pending_info_request=self.days_ago(42))
# Mozilla-disabled addon
addon_factory(name='Disabled Addön', status=amo.STATUS_DISABLED)
# Incomplete addon with expired info request.
addon5 = addon_factory(name=u'Incomplete Addön 5',
status=amo.STATUS_NULL)
AddonReviewerFlags.objects.create(
addon=addon5,
pending_info_request=self.days_ago(42))
# Incomplete addon
addon_factory(name='Incomplete Addön', status=amo.STATUS_NULL)
# Invisible (user-disabled) addon with expired info request.
addon6 = addon_factory(name=u'Incomplete Addön 5',
status=amo.STATUS_APPROVED,
disabled_by_user=True)
AddonReviewerFlags.objects.create(
addon=addon6,
pending_info_request=self.days_ago(42))
# Invisible (user-disabled) addon
addon_factory(name='Invisible Addön', status=amo.STATUS_APPROVED,
disabled_by_user=True)
pending_rejection = addon_factory(name='Pending Rejection Addôn')
VersionReviewerFlags.objects.create(
version=pending_rejection.current_version,
pending_rejection=datetime.now() + timedelta(days=4)
)
# Rating
rating = Rating.objects.create(
addon=addon1, version=addon1.current_version, user=self.user,
flag=True, body=u'This âdd-on sucks!!111', rating=1,
addon=addon, version=addon.current_version, user=self.user,
flag=True, body='This âdd-on sucks!!111', rating=1,
editorreview=True)
rating.ratingflag_set.create()
@ -689,7 +664,6 @@ class TestDashboard(TestCase):
reverse('reviewers.unlisted_queue_all'),
'https://wiki.mozilla.org/Add-ons/Reviewers/Guide',
reverse('reviewers.motd'),
reverse('reviewers.queue_expired_info_requests'),
reverse('reviewers.queue_pending_rejection'),
]
links = [link.attrib['href'] for link in doc('.dashboard a')]
@ -709,7 +683,7 @@ class TestDashboard(TestCase):
'Ratings Awaiting Moderation (1)')
# admin tools
assert (doc('.dashboard a')[24].text ==
'Expired Information Requests (2)')
'Add-ons Pending Rejection (1)')
def test_can_see_all_through_reviewer_view_all_permission(self):
self.grant_permission(self.user, 'ReviewerTools:View')
@ -741,7 +715,6 @@ class TestDashboard(TestCase):
reverse('reviewers.unlisted_queue_all'),
'https://wiki.mozilla.org/Add-ons/Reviewers/Guide',
reverse('reviewers.motd'),
reverse('reviewers.queue_expired_info_requests'),
reverse('reviewers.queue_pending_rejection'),
]
links = [link.attrib['href'] for link in doc('.dashboard a')]
@ -1410,7 +1383,6 @@ class TestQueueBasics(QueueTest):
doc = pq(response.content)
links = doc('.tabnav li a').map(lambda i, e: e.attrib['href'])
expected.extend([
reverse('reviewers.queue_expired_info_requests'),
reverse('reviewers.queue_pending_rejection'),
])
assert links == expected
@ -2194,11 +2166,11 @@ class TestAutoApprovedQueue(QueueTest):
def test_results(self):
self.login_with_permission()
self.generate_files()
with self.assertNumQueries(27):
# 27 queries is a lot, but it used to be much much worse.
with self.assertNumQueries(26):
# 26 queries is a lot, but it used to be much much worse.
# - 2 for savepoints because we're in tests
# - 2 for user/groups
# - 12 for various queue counts, including current one
# - 11 for various queue counts, including current one
# (unfortunately duplicated because it appears in two
# completely different places)
# - 3 for the addons in the queues and their files (regardless of
@ -2263,84 +2235,6 @@ class TestAutoApprovedQueue(QueueTest):
self._test_results()
class TestExpiredInfoRequestsQueue(QueueTest):
def setUp(self):
super(TestExpiredInfoRequestsQueue, self).setUp()
self.url = reverse('reviewers.queue_expired_info_requests')
def generate_files(self):
# Extra add-on with no pending info request.
addon_factory(name=u'Extra Addôn 1')
# Extra add-on with a non-expired pending info request.
extra_addon = addon_factory(name=u'Extra Addôn 2')
AddonReviewerFlags.objects.create(
addon=extra_addon,
pending_info_request=datetime.now() + timedelta(days=1))
# Pending addon with expired info request.
addon1 = addon_factory(name=u'Pending Addön 1',
status=amo.STATUS_NOMINATED)
AddonReviewerFlags.objects.create(
addon=addon1,
pending_info_request=self.days_ago(2))
# Public addon with expired info request.
addon2 = addon_factory(name=u'Public Addön 2',
status=amo.STATUS_APPROVED)
AddonReviewerFlags.objects.create(
addon=addon2,
pending_info_request=self.days_ago(42))
# Deleted addon with expired info request.
addon3 = addon_factory(name=u'Deleted Addön 3',
status=amo.STATUS_DELETED)
AddonReviewerFlags.objects.create(
addon=addon3,
pending_info_request=self.days_ago(42))
# Mozilla-disabled addon with expired info request.
addon4 = addon_factory(name=u'Disabled Addön 4',
status=amo.STATUS_DISABLED)
AddonReviewerFlags.objects.create(
addon=addon4,
pending_info_request=self.days_ago(42))
# Incomplete addon with expired info request.
addon5 = addon_factory(name=u'Incomplete Addön 5',
status=amo.STATUS_NULL)
AddonReviewerFlags.objects.create(
addon=addon5,
pending_info_request=self.days_ago(42))
# Invisible (user-disabled) addon with expired info request.
addon6 = addon_factory(name=u'Incomplete Addön 5',
status=amo.STATUS_APPROVED,
disabled_by_user=True)
AddonReviewerFlags.objects.create(
addon=addon6,
pending_info_request=self.days_ago(42))
self.expected_addons = [addon2, addon1]
def test_results_no_permission(self):
# Addon reviewer doesn't have access.
response = self.client.get(self.url)
assert response.status_code == 403
# Regular user doesn't have access.
self.client.logout()
assert self.client.login(email='regular@mozilla.com')
response = self.client.get(self.url)
assert response.status_code == 403
def test_results(self):
self.grant_permission(self.user, 'Reviews:Admin')
self.generate_files()
self._test_results()
class TestContentReviewQueue(QueueTest):
def setUp(self):
@ -2465,11 +2359,11 @@ class TestContentReviewQueue(QueueTest):
def test_results(self):
self.login_with_permission()
self.generate_files()
with self.assertNumQueries(27):
# 27 queries is a lot, but it used to be much much worse.
with self.assertNumQueries(26):
# 26 queries is a lot, but it used to be much much worse.
# - 2 for savepoints because we're in tests
# - 2 for user/groups
# - 12 for various queue counts, including current one
# - 11 for various queue counts, including current one
# (unfortunately duplicated because it appears in two
# completely different places)
# - 3 for the addons in the queues and their files (regardless of
@ -2494,7 +2388,7 @@ class TestContentReviewQueue(QueueTest):
self.generate_files()
self._test_queue_layout(
'Content Review', tab_position=0, total_addons=5, total_queues=3)
'Content Review', tab_position=0, total_addons=5, total_queues=2)
def test_pending_rejection_filtered_out(self):
self.login_with_permission()
@ -2628,7 +2522,7 @@ class TestScannersReviewQueue(QueueTest):
self._test_queue_layout(
'Flagged By Scanners',
tab_position=2, total_addons=4, total_queues=11, per_page=1)
tab_position=2, total_addons=4, total_queues=10, per_page=1)
class TestPendingRejectionReviewQueue(QueueTest):
@ -3360,7 +3254,7 @@ class TestReview(ReviewBase):
assert ActivityLog.objects.filter(
action=comment_version.id).count() == 1
def test_info_requested(self):
def test_reviewer_reply(self):
response = self.client.post(self.url, {'action': 'reply',
'comments': 'hello sailor'})
assert response.status_code == 302
@ -3372,7 +3266,7 @@ class TestReview(ReviewBase):
'comments': 'hello sailor'})
assert response.status_code == 302
def test_info_requested_canned_response(self):
def test_reviewer_reply_canned_response(self):
response = self.client.post(self.url, {'action': 'reply',
'comments': 'hello sailor',
'canned_response': 'foo'})
@ -3852,7 +3746,6 @@ class TestReview(ReviewBase):
assert not doc('#disable_auto_approval')
assert not doc('#enable_auto_approval')
assert not doc('#clear_auto_approval_delayed_until')
assert not doc('#clear_pending_info_request')
assert not doc('#clear_pending_rejections')
assert not doc('#deny_resubmission')
assert not doc('#allow_resubmission')
@ -4071,20 +3964,6 @@ class TestReview(ReviewBase):
assert not doc('#disable_auto_approval')
assert not doc('#enable_auto_approval')
def test_clear_pending_info_request_as_admin(self):
self.login_as_admin()
response = self.client.get(self.url)
assert response.status_code == 200
doc = pq(response.content)
assert not doc('#clear_pending_info_request')
AddonReviewerFlags.objects.create(
addon=self.addon, pending_info_request=self.days_ago(1))
response = self.client.get(self.url)
assert response.status_code == 200
doc = pq(response.content)
assert doc('#clear_pending_info_request')
def test_clear_pending_rejections_as_admin(self):
self.login_as_admin()
response = self.client.get(self.url)
@ -6457,7 +6336,6 @@ class TestAddonReviewerViewSet(TestCase):
def test_patch_flags_change_everything(self):
AddonReviewerFlags.objects.create(
addon=self.addon,
pending_info_request=self.days_ago(1),
auto_approval_disabled=True,
auto_approval_delayed_until=self.days_ago(42))
self.grant_permission(self.user, 'Reviews:Admin')
@ -6469,7 +6347,6 @@ class TestAddonReviewerViewSet(TestCase):
'needs_admin_code_review': True,
'needs_admin_content_review': True,
'needs_admin_theme_review': True,
'pending_info_request': None,
}
response = self.client.patch(self.flags_url, data)
assert response.status_code == 200
@ -6483,11 +6360,6 @@ class TestAddonReviewerViewSet(TestCase):
assert reviewer_flags.needs_admin_code_review is True
assert reviewer_flags.needs_admin_content_review is True
assert reviewer_flags.needs_admin_theme_review is True
assert reviewer_flags.pending_info_request is None
assert ActivityLog.objects.count() == 1
activity_log = ActivityLog.objects.latest('pk')
assert activity_log.action == amo.LOG.ADMIN_ALTER_INFO_REQUEST.id
assert activity_log.arguments[0] == self.addon
def test_deny_resubmission(self):
self.grant_permission(self.user, 'Reviews:Admin')
@ -8270,4 +8142,4 @@ class TestMadQueue(QueueTest):
self.grant_permission(self.user, 'Reviews:Admin')
self._test_queue_layout('Flagged for Human Review', tab_position=2,
total_addons=3, total_queues=5, per_page=1)
total_addons=3, total_queues=4, per_page=1)

Просмотреть файл

@ -31,8 +31,6 @@ urlpatterns = (
name='reviewers.queue_scanners'),
url(r'queue/pending_rejection', views.queue_pending_rejection,
name='reviewers.queue_pending_rejection'),
url(r'^queue/expired_info_requests', views.queue_expired_info_requests,
name='reviewers.queue_expired_info_requests'),
url(r'^unlisted_queue/all$', views.unlisted_list,
name='reviewers.unlisted_queue_all'),
url(r'^moderationlog$', views.ratings_moderation_log,

Просмотреть файл

@ -207,19 +207,6 @@ class ModernAddonQueueTable(ReviewerQueueTable):
render_last_content_review = render_last_human_review
class ExpiredInfoRequestsTable(ModernAddonQueueTable):
deadline = tables.Column(
verbose_name=_(u'Information Request Deadline'),
accessor='reviewerflags.pending_info_request')
class Meta(ModernAddonQueueTable.Meta):
fields = ('addon_name', 'flags', 'last_human_review', 'weight',
'deadline')
def render_deadline(self, value):
return naturaltime(value) if value else ''
class PendingRejectionTable(ModernAddonQueueTable):
deadline = tables.Column(
verbose_name=_('Pending Rejection Deadline'),

Просмотреть файл

@ -70,8 +70,8 @@ from olympia.reviewers.serializers import (
DiffableVersionSerializer, DraftCommentSerializer, FileInfoSerializer,
)
from olympia.reviewers.utils import (
AutoApprovedTable, ContentReviewTable, ExpiredInfoRequestsTable,
MadReviewTable, PendingRejectionTable, ReviewHelper, ScannersReviewTable,
AutoApprovedTable, ContentReviewTable, MadReviewTable,
PendingRejectionTable, ReviewHelper, ScannersReviewTable,
ViewUnlistedAllListTable, view_table_factory)
from olympia.users.models import UserProfile
from olympia.versions.models import Version, VersionReviewerFlags
@ -267,10 +267,6 @@ def dashboard(request):
if view_all or acl.action_allowed(
request, amo.permissions.REVIEWS_ADMIN):
sections[ugettext('Admin Tools')] = [(
ugettext('Expired Information Requests ({0})'.format(
queue_counts['expired_info_requests'])),
reverse('reviewers.queue_expired_info_requests')
), (
ugettext('Add-ons Pending Rejection ({0})').format(
queue_counts['pending_rejection']),
reverse('reviewers.queue_pending_rejection')
@ -507,13 +503,6 @@ def fetch_queue_counts(admin_reviewer):
qs = filter_admin_review_for_legacy_queue(qs)
return qs.count
expired = (
Addon.objects.filter(
reviewerflags__pending_info_request__lt=datetime.now(),
status__in=(amo.STATUS_NOMINATED, amo.STATUS_APPROVED),
disabled_by_user=False)
.order_by('reviewerflags__pending_info_request'))
counts = {
'extension': construct_query_from_sql_model(
ViewExtensionQueue),
@ -535,7 +524,6 @@ def fetch_queue_counts(admin_reviewer):
'scanners': (
Addon.objects.get_scanners_queue(
admin_reviewer=admin_reviewer).count),
'expired_info_requests': expired.count,
'pending_rejection': (
Addon.objects.get_pending_rejection_queue(
admin_reviewer=admin_reviewer).count),
@ -629,18 +617,6 @@ def queue_auto_approved(request):
qs=qs, SearchForm=None)
@permission_required(amo.permissions.REVIEWS_ADMIN)
def queue_expired_info_requests(request):
qs = (
Addon.objects.filter(
reviewerflags__pending_info_request__lt=datetime.now(),
status__in=(amo.STATUS_NOMINATED, amo.STATUS_APPROVED),
disabled_by_user=False)
.order_by('reviewerflags__pending_info_request'))
return _queue(request, ExpiredInfoRequestsTable, 'expired_info_requests',
qs=qs, SearchForm=None)
@permission_or_tools_view_required(amo.permissions.ADDONS_REVIEW)
def queue_scanners(request):
admin_reviewer = is_admin_reviewer(request)
@ -1280,9 +1256,6 @@ class AddonReviewerViewSet(GenericViewSet):
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)