Merge pull request #3494 from eviljeff/i3088-clean-up-preliminary-review

bye bye preliminary - devhub
This commit is contained in:
Andrew Williamson 2016-09-15 12:16:51 +01:00 коммит произвёл GitHub
Родитель ec798bb335 5d37a9c1c6
Коммит f73d224ff6
31 изменённых файлов: 148 добавлений и 899 удалений

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

@ -630,11 +630,6 @@ class Addon(OnChangeMixin, ModelBase):
# with on a file-by-file basis. # with on a file-by-file basis.
return not self.is_listed return not self.is_listed
@property
def is_sideload(self):
# An add-on can side-load if it has been fully reviewed.
return self.status in (amo.STATUS_NOMINATED, amo.STATUS_PUBLIC)
@amo.cached_property(writable=True) @amo.cached_property(writable=True)
def listed_authors(self): def listed_authors(self):
return UserProfile.objects.filter( return UserProfile.objects.filter(

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

@ -11,7 +11,6 @@ from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _, ugettext_lazy as _lazy from django.utils.translation import ugettext as _, ugettext_lazy as _lazy
import commonware import commonware
import waffle
from quieter_formset.formset import BaseModelFormSet from quieter_formset.formset import BaseModelFormSet
from olympia.access import acl from olympia.access import acl
@ -538,15 +537,6 @@ class NewAddonForm(AddonUploadForm):
help_text=_lazy( help_text=_lazy(
u'Check this option if you intend to distribute your add-on on ' u'Check this option if you intend to distribute your add-on on '
u'your own and only need it to be signed by Mozilla.')) u'your own and only need it to be signed by Mozilla.'))
is_sideload = forms.BooleanField(
initial=False,
required=False,
label=_lazy(u'This add-on will be bundled with an application '
u'installer.'),
help_text=_lazy(u'Add-ons that are bundled with application '
u'installers will be code reviewed '
u'by Mozilla before they are signed and are held to a '
u'higher quality standard.'))
def clean(self): def clean(self):
if not self.errors: if not self.errors:
@ -557,16 +547,6 @@ class NewAddonForm(AddonUploadForm):
class NewVersionForm(NewAddonForm): class NewVersionForm(NewAddonForm):
nomination_type = forms.TypedChoiceField(
choices=(
('', ''),
(amo.STATUS_NOMINATED, _lazy('Full Review')),
(amo.STATUS_UNREVIEWED, _lazy('Preliminary Review')),
),
coerce=int, empty_value=None, required=False,
error_messages={
'required': _lazy(u'Please choose a review nomination type')
})
beta = forms.BooleanField( beta = forms.BooleanField(
required=False, required=False,
help_text=_lazy(u'A file with a version ending with ' help_text=_lazy(u'A file with a version ending with '
@ -576,9 +556,6 @@ class NewVersionForm(NewAddonForm):
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
self.addon = kw.pop('addon') self.addon = kw.pop('addon')
super(NewVersionForm, self).__init__(*args, **kw) super(NewVersionForm, self).__init__(*args, **kw)
if (not waffle.flag_is_active(self.request, 'no-prelim-review') and
self.addon.status == amo.STATUS_NULL):
self.fields['nomination_type'].required = True
def clean(self): def clean(self):
if not self.errors: if not self.errors:
@ -697,15 +674,6 @@ FileFormSet = modelformset_factory(File, formset=BaseFileFormSet,
form=FileForm, can_delete=True, extra=0) form=FileForm, can_delete=True, extra=0)
class ReviewTypeForm(forms.Form):
_choices = [(k, Addon.STATUS_CHOICES[k]) for k in
(amo.STATUS_UNREVIEWED, amo.STATUS_NOMINATED)]
review_type = forms.TypedChoiceField(
choices=_choices, widget=forms.HiddenInput,
coerce=int, empty_value=None,
error_messages={'required': _lazy(u'A review type must be selected.')})
class Step3Form(AddonFormBasic): class Step3Form(AddonFormBasic):
description = TransField(widget=TransTextarea, required=False) description = TransField(widget=TransTextarea, required=False)
tags = None tags = None

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

@ -12,7 +12,6 @@ from olympia.amo.urlresolvers import reverse
from olympia.amo.helpers import breadcrumbs, impala_breadcrumbs, page_title from olympia.amo.helpers import breadcrumbs, impala_breadcrumbs, page_title
from olympia.access import acl from olympia.access import acl
from olympia.addons.helpers import new_context from olympia.addons.helpers import new_context
from olympia.addons.models import Addon
from olympia.devhub.models import ActivityLog from olympia.devhub.models import ActivityLog
from olympia.compat.models import CompatReport from olympia.compat.models import CompatReport
from olympia.files.models import File from olympia.files.models import File
@ -124,26 +123,9 @@ def source_form_field(field):
return {'field': field} return {'field': field}
@register.function
def status_choices(addon):
"""
Return a dict like File.STATUS_CHOICES customized for the addon status.
"""
# Show "awaiting full review" for unreviewed files on that track.
choices = dict(File.STATUS_CHOICES)
if addon.status in (amo.STATUS_NOMINATED, amo.STATUS_LITE_AND_NOMINATED,
amo.STATUS_PUBLIC):
choices[amo.STATUS_UNREVIEWED] = (
Addon.STATUS_CHOICES[amo.STATUS_NOMINATED])
elif addon.status in (amo.STATUS_UNREVIEWED, amo.STATUS_LITE):
choices[amo.STATUS_UNREVIEWED] = (
Addon.STATUS_CHOICES[amo.STATUS_UNREVIEWED])
return choices
@register.inclusion_tag('devhub/versions/file_status_message.html') @register.inclusion_tag('devhub/versions/file_status_message.html')
def file_status_message(file, addon): def file_status_message(file):
choices = status_choices(addon) choices = File.STATUS_CHOICES
return {'fileid': file.id, 'platform': file.get_platform_display(), return {'fileid': file.id, 'platform': file.get_platform_display(),
'created': datetime(file.created), 'created': datetime(file.created),
'status': choices[file.status], 'status': choices[file.status],
@ -152,10 +134,10 @@ def file_status_message(file, addon):
@register.function @register.function
def dev_files_status(files, addon): def dev_files_status(files):
"""Group files by their status (and files per status).""" """Group files by their status (and files per status)."""
status_count = defaultdict(int) status_count = defaultdict(int)
choices = status_choices(addon) choices = File.STATUS_CHOICES
for file in files: for file in files:
status_count[file.status] += 1 status_count[file.status] += 1
@ -168,12 +150,9 @@ def dev_files_status(files, addon):
def status_class(addon): def status_class(addon):
classes = { classes = {
amo.STATUS_NULL: 'incomplete', amo.STATUS_NULL: 'incomplete',
amo.STATUS_UNREVIEWED: 'unreviewed',
amo.STATUS_NOMINATED: 'nominated', amo.STATUS_NOMINATED: 'nominated',
amo.STATUS_PUBLIC: 'fully-approved', amo.STATUS_PUBLIC: 'fully-approved',
amo.STATUS_DISABLED: 'admin-disabled', amo.STATUS_DISABLED: 'admin-disabled',
amo.STATUS_LITE: 'lite',
amo.STATUS_LITE_AND_NOMINATED: 'lite-nom',
amo.STATUS_DELETED: 'deleted', amo.STATUS_DELETED: 'deleted',
amo.STATUS_REJECTED: 'rejected', amo.STATUS_REJECTED: 'rejected',
} }

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

@ -62,31 +62,25 @@ def validate(file_, listed=None, subtask=None):
return result return result
def validate_and_submit(addon, file_, listed=None, def validate_and_submit(addon, file_, listed=None):
disallow_preliminary_review=False):
return validate( return validate(
file_, listed=listed, subtask=submit_file.si( file_, listed=listed, subtask=submit_file.si(addon.pk, file_.pk))
addon.pk, file_.pk,
disallow_preliminary_review=disallow_preliminary_review))
@task @task
@write @write
def submit_file(addon_pk, upload_pk, disallow_preliminary_review=False): def submit_file(addon_pk, upload_pk):
addon = Addon.unfiltered.get(pk=addon_pk) addon = Addon.unfiltered.get(pk=addon_pk)
upload = FileUpload.objects.get(pk=upload_pk) upload = FileUpload.objects.get(pk=upload_pk)
if upload.passed_all_validations: if upload.passed_all_validations:
create_version_for_upload( create_version_for_upload(addon, upload)
addon, upload,
disallow_preliminary_review=disallow_preliminary_review)
else: else:
log.info('Skipping version creation for {upload_uuid} that failed ' log.info('Skipping version creation for {upload_uuid} that failed '
'validation'.format(upload_uuid=upload.uuid)) 'validation'.format(upload_uuid=upload.uuid))
@atomic @atomic
def create_version_for_upload(addon, upload, def create_version_for_upload(addon, upload):
disallow_preliminary_review=False):
fileupload_exists = addon.fileupload_set.filter( fileupload_exists = addon.fileupload_set.filter(
created__gt=upload.created, version=upload.version).exists() created__gt=upload.created, version=upload.version).exists()
version_exists = Version.unfiltered.filter( version_exists = Version.unfiltered.filter(
@ -106,13 +100,8 @@ def create_version_for_upload(addon, upload,
# The add-on's status will be STATUS_NULL when its first version is # The add-on's status will be STATUS_NULL when its first version is
# created because the version has no files when it gets added and it # created because the version has no files when it gets added and it
# gets flagged as invalid. We need to manually set the status. # gets flagged as invalid. We need to manually set the status.
# TODO: Handle sideload add-ons. This assumes the user wants a prelim
# review since listed and sideload aren't supported for creation yet.
if addon.status == amo.STATUS_NULL: if addon.status == amo.STATUS_NULL:
if disallow_preliminary_review: addon.update(status=amo.STATUS_NOMINATED)
addon.update(status=amo.STATUS_NOMINATED)
else:
addon.update(status=amo.STATUS_LITE)
auto_sign_version(version, is_beta=version.is_beta) auto_sign_version(version, is_beta=version.is_beta)

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

@ -67,7 +67,6 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% if waffle.flag('no-prelim-review') %}
<tr> <tr>
<th> <th>
{{ tip(_("Experimental?"), {{ tip(_("Experimental?"),
@ -81,7 +80,6 @@
_("This add-on is ready for general use.")) }} _("This add-on is ready for general use.")) }}
</td> </td>
</tr> </tr>
{% endif %}
<tr> <tr>
<th> <th>
{{ tip(_("Categories"), {{ tip(_("Categories"),

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

@ -46,7 +46,6 @@
</div> </div>
</div> </div>
{% if addon.is_listed %} {% if addon.is_listed %}
{% if waffle.flag('no-prelim-review') %}
<div class="addon-submission-field"> <div class="addon-submission-field">
<label for="{{ form.is_experimental.auto_id }}"> <label for="{{ form.is_experimental.auto_id }}">
{{ form.is_experimental }} {{ form.is_experimental }}
@ -59,7 +58,6 @@
}}">?</span> }}">?</span>
</label> </label>
</div> </div>
{% endif %}
<div id="addon-categories-edit" class="addon-submission-field" <div id="addon-categories-edit" class="addon-submission-field"
data-max-categories="{{ amo.MAX_CATEGORIES }}"> data-max-categories="{{ amo.MAX_CATEGORIES }}">
{{ cat_form.non_form_errors() }} {{ cat_form.non_form_errors() }}

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

@ -8,9 +8,7 @@
<h3>{{ _("You're done!") }}</h3> <h3>{{ _("You're done!") }}</h3>
{% if addon.is_listed %} {% if addon.is_listed %}
<p> <p>
{% if addon.status == amo.STATUS_UNREVIEWED %} {% if addon.status == amo.STATUS_NOMINATED %}
{{ _('Your add-on has been submitted to the Preliminary Review queue.') }}
{% elif addon.status == amo.STATUS_NOMINATED %}
{{ _('Your add-on has been submitted to the Full Review queue.') }} {{ _('Your add-on has been submitted to the Full Review queue.') }}
{% endif %} {% endif %}
</p> </p>
@ -47,7 +45,7 @@
</p> </p>
</div> </div>
{% else %} {% else %}
{% set signed = addon.status in [amo.STATUS_PUBLIC, amo.STATUS_LITE] %} {% set signed = addon.status == amo.STATUS_PUBLIC %}
{% if signed %} {% if signed %}
<p> <p>
{{ _('Your add-on has been signed and it\'s ready to use. You can download it here:') }} {{ _('Your add-on has been signed and it\'s ready to use. You can download it here:') }}
@ -59,9 +57,7 @@
</p> </p>
{% else %} {% else %}
<p> <p>
{% if addon.status == amo.STATUS_UNREVIEWED %} {% if addon.status == amo.STATUS_NOMINATED %}
{{ _('Your add-on has been submitted to the Unlisted Preliminary Review queue.') }}
{% elif addon.status == amo.STATUS_NOMINATED %}
{{ _('Your add-on has been submitted to the Unlisted Full Review queue.') }} {{ _('Your add-on has been submitted to the Unlisted Full Review queue.') }}
{% endif %} {% endif %}
</p> </p>

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

@ -1,68 +0,0 @@
{% extends "devhub/addons/submit/base.html" %}
{% set learn_more_url = 'https://developer.mozilla.org/en-US/Add-ons/AMO/Policy/Reviews' %}
{% block title %}{{ dev_page_title(_('Step 6'), addon) }}{% endblock %}
{% block primary %}
<h3>{{ _('Step 6. Select a Review Process') }}</h3>
<p>
{% trans %}
All add-ons hosted in our gallery must be reviewed by an editor before
they appear in categories or search results. While waiting for review,
your add-on can still be accessed through its direct URL. Please choose
the review process below that best fits your add-on.
{% endtrans %}
</p>
<form class="select-review" method="post">
{{ csrf() }}
{{ review_type_form.non_field_errors() }}
{{ review_type_form.review_type }}
{{ review_type_form.review_type.errors }}
<div class="review-type">
<div class="highlight">
<h4>{{ _('Full Review') }}</h4>
<p>
{% trans url=learn_more_url %}
A complete review of your add-on's source and functionality.
<a href="{{ url }}">Learn more&hellip;</a>
{% endtrans %}
</p>
<ul>
<li>{{ _('Appropriate for polished add-ons') }}</li>
<li>{{ _('Required if add-on is bundled in an installer') }}</li>
<li>{{ _('Review should take place within 10 days') }}</li>
<li>{{ _('Review of subsequent versions within 5 days') }}</li>
<li>{{ _('Warning-free installation and no feature limitations') }}</li>
</ul>
<p class="submit-buttons">
<button type="submit" name="review_type" value="{{ amo.STATUS_NOMINATED }}">
{{ _('Choose Full Review') }}
</button>
</p>
</div>
</div>
<div class="review-type">
<div class="highlight">
<h4>{{ _('Preliminary Review') }}</h4>
<p>
{% trans url=learn_more_url %}
A faster review of your add-on's source for any major problems.
<a href="{{ url }}">Learn more&hellip;</a>
{% endtrans %}
</p>
<ul>
<li>{{ _('Appropriate for experimental add-ons') }}</li>
<li>{{ _('Review should take place within 3 days') }}</li>
<li>{{ _('Some feature limitations') }}</li>
<li>{{ _('Binary and obfuscated add-ons ineligible') }}</li>
</ul>
<p class="submit-buttons">
<button type="submit" name="review_type" value="{{ amo.STATUS_UNREVIEWED }}">
{{ _('Choose Preliminary Review') }}
</button>
</p>
</div>
</div>
</form>
{% endblock %}

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

@ -4,24 +4,14 @@
{# List of steps: (text, class). A class of 'all' means the step is relevant {# List of steps: (text, class). A class of 'all' means the step is relevant
to listed or unlisted addons, a class of 'listed' means it's only relevant to listed or unlisted addons, a class of 'listed' means it's only relevant
to listed addons, not unlisted ones. #} to listed addons, not unlisted ones. #}
{% if waffle.flag('no-prelim-review') %} {% set NAV = ((_('Getting Started'), 'all'),
{% set NAV = ((_('Getting Started'), 'all'),
(_('Upload your add-on'), 'all'), (_('Upload your add-on'), 'all'),
(_('Describe your add-on'), 'all'), (_('Describe your add-on'), 'all'),
(_('Add images'), 'listed'), (_('Add images'), 'listed'),
(_('Select a license'), 'listed'), (_('Select a license'), 'listed'),
(_('n/a'), 'hidden'),
(_("You're done!"), 'all')) %} (_("You're done!"), 'all')) %}
{% else %}
{% set NAV = ((_('Getting Started'), 'all'), {% set MAX = 6 %}
(_('Upload your add-on'), 'all'),
(_('Describe your add-on'), 'all'),
(_('Add images'), 'listed'),
(_('Select a license'), 'listed'),
(_('Select a review process'), 'listed'),
(_("You're done!"), 'all')) %}
{% endif %}
{% set MAX = 7 %}
{% set BASE = 'devhub.submit.%s' %} {% set BASE = 'devhub.submit.%s' %}
<div class="highlight"> <div class="highlight">
<hgroup> <hgroup>

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

@ -28,21 +28,12 @@
<span class="tip tooltip" <span class="tip tooltip"
title="{{ new_addon_form.is_unlisted.help_text }}">?</span> title="{{ new_addon_form.is_unlisted.help_text }}">?</span>
</label> </label>
{% if not waffle.flag('no-prelim-review') %}
<label for="{{ new_addon_form.is_sideload.auto_id }}">
{{ new_addon_form.is_sideload }}
{{ new_addon_form.is_sideload.label }}
<span class="tip tooltip"
title="{{ new_addon_form.is_sideload.help_text }}">?</span>
</label>
{% endif %}
</div> </div>
</div> </div>
<input type="file" id="upload-addon" <input type="file" id="upload-addon"
data-upload-url="{{ url('devhub.upload') }}" data-upload-url="{{ url('devhub.upload') }}"
data-upload-url-listed="{{ url('devhub.upload') }}" data-upload-url-listed="{{ url('devhub.upload') }}"
data-upload-url-unlisted="{{ url('devhub.upload_unlisted') }}" data-upload-url-unlisted="{{ url('devhub.upload_unlisted') }}">
data-upload-url-sideload="{{ url('devhub.upload_sideload') }}">
{{ new_addon_form.non_field_errors() }} {{ new_addon_form.non_field_errors() }}

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

@ -1,8 +1,4 @@
{% if full_review %}
<p>Thanks for submitting your {{ app }} Add-on to <a href="https://addons.mozilla.org">addons.mozilla.org</a> (AMO)! Your add-on has been added to the Full Review queue.</p> <p>Thanks for submitting your {{ app }} Add-on to <a href="https://addons.mozilla.org">addons.mozilla.org</a> (AMO)! Your add-on has been added to the Full Review queue.</p>
{% else %}
<p>Thanks for submitting your {{ app }} Add-on to <a href="https://addons.mozilla.org">addons.mozilla.org</a> (AMO)! Your add-on has been added to the Preliminary Review queue.</p>
{% endif %}
<p>We will contact you if we need more information. After it is reviewed, you will receive an email notification and your add-on will appear in categories and search results. While awaiting review, your add-on can still be accessed and installed directly from its detail page:</p> <p>We will contact you if we need more information. After it is reviewed, you will receive an email notification and your add-on will appear in categories and search results. While awaiting review, your add-on can still be accessed and installed directly from its detail page:</p>

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

@ -26,16 +26,6 @@
{% elif addon.status == amo.STATUS_NULL %} {% elif addon.status == amo.STATUS_NULL %}
{{ status_and_tip(addon, _('Please complete your add-on.'), {{ status_and_tip(addon, _('Please complete your add-on.'),
url=url('devhub.submit.resume', addon.slug)) }} url=url('devhub.submit.resume', addon.slug)) }}
{% elif addon.status == amo.STATUS_PENDING %}
{{ status_and_tip(addon, _('You will receive an email when the review is complete.')) }}
{% elif addon.status == amo.STATUS_UNREVIEWED %}
{{ status_and_tip(addon,
_("You will receive an email when the review is complete. Until "
"then, your add-on is not listed in our gallery but can be "
"accessed directly from its details page.")
if addon.is_listed else
_("You will receive an email when the review is "
"complete and your add-on is signed.")) }}
{% elif addon.status == amo.STATUS_NOMINATED %} {% elif addon.status == amo.STATUS_NOMINATED %}
{{ status_and_tip(addon, {{ status_and_tip(addon,
_("You will receive an email when the review is complete. Until " _("You will receive an email when the review is complete. Until "
@ -57,23 +47,6 @@
"longer shown in our gallery. If you have any questions, " "longer shown in our gallery. If you have any questions, "
"please email amo-admins@mozilla.org."), "please email amo-admins@mozilla.org."),
url=(addon.get_dev_url('versions') + '#version-upload')) }} url=(addon.get_dev_url('versions') + '#version-upload')) }}
{% elif addon.status == amo.STATUS_LITE %}
{{ status_and_tip(addon,
_("Your add-on is displayed in our gallery as experimental "
"and users are receiving automatic updates. Some features "
"are unavailable to your add-on.")
if addon.is_listed else
_('Your add-on has been signed.')) }}
{% elif addon.status == amo.STATUS_LITE_AND_NOMINATED %}
{{ status_and_tip(addon,
_("You will receive an email when the full review is complete. "
"Until then, your add-on is displayed in our gallery as "
"experimental and users are receiving automatic updates. "
"Some features are unavailable to your add-on.")
if addon.is_listed else
_("You will receive an email when the full review is "
"complete, making you able to bundle your add-on with an "
"application installer.")) }}
{% endif %} {% endif %}
</strong> </strong>
</li> </li>

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

@ -6,7 +6,7 @@
</td> </td>
<td>{{ file.size|filesizeformat }}</td> <td>{{ file.size|filesizeformat }}</td>
<td>{{ form.platform }}</td> <td>{{ form.platform }}</td>
<td>{{ status_choices(addon)[file.status] }}</td> <td>{{ choices[file.status] }}</td>
<td> <td>
<span class="js-hidden"> <span class="js-hidden">
<span class="delete">{{ form.DELETE }}</span> <span class="delete">{{ form.DELETE }}</span>

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

@ -47,20 +47,13 @@
<span class="tip tooltip" <span class="tip tooltip"
title="{{ new_addon_form.is_unlisted.help_text }}">?</span> title="{{ new_addon_form.is_unlisted.help_text }}">?</span>
</label> </label>
<label for="{{ new_addon_form.is_sideload.auto_id }}">
{{ new_addon_form.is_sideload }}
{{ new_addon_form.is_sideload.label }}
<span class="tip tooltip"
title="{{ new_addon_form.is_sideload.help_text }}">?</span>
</label>
</div> </div>
</div> </div>
<input type="file" id="upload-addon" <input type="file" id="upload-addon"
data-upload-url="{{ url('devhub.standalone_upload') }}" data-upload-url="{{ url('devhub.standalone_upload') }}"
data-upload-url-listed="{{ url('devhub.standalone_upload') }}" data-upload-url-listed="{{ url('devhub.standalone_upload') }}"
data-upload-url-unlisted="{{ url('devhub.standalone_upload_unlisted') }}" data-upload-url-unlisted="{{ url('devhub.standalone_upload_unlisted') }}"">
data-upload-url-sideload="{{ url('devhub.standalone_upload_sideload') }}">
</section> </section>
</form> </form>

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

@ -1,7 +1,6 @@
<div class="add-file-modal upload-file modal hidden"> <div class="add-file-modal upload-file modal hidden">
<form method="post" id="upload-file" class="new-addon-file" action="{{ action }}" enctype="multipart/form-data" <form method="post" id="upload-file" class="new-addon-file" action="{{ action }}" enctype="multipart/form-data"
data-addon-is-listed="{% if addon.is_listed %}true{% else %}false{% endif %}" data-addon-is-listed="{% if addon.is_listed %}true{% else %}false{% endif %}">
data-addon-is-sideload="{% if not addon.is_listed and addon.status in [amo.STATUS_PUBLIC, amo.STATUS_NOMINATED] %}true{% else %}false{% endif %}">
<h3>{{ title }}</h3> <h3>{{ title }}</h3>
<div class="upload-file-box"> <div class="upload-file-box">
<p> <p>
@ -30,12 +29,6 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% if not waffle.flag('no-prelim-review') and addon.status == amo.STATUS_NULL %}
<div class="nomination-type">
<label>{{ _('Which review type would you like to nominate for?') }}</label>
{{ new_file_form.nomination_type }}
</div>
{% endif %}
<div class="beta-status hide"> <div class="beta-status hide">
<label>{{ new_file_form.beta }} {{ _('Only publish this version to my beta channel.') }}</label> <label>{{ new_file_form.beta }} {{ _('Only publish this version to my beta channel.') }}</label>
<span class="tip tooltip" title="{{ new_file_form.beta.help_text }}">?</span> <span class="tip tooltip" title="{{ new_file_form.beta.help_text }}">?</span>

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

@ -101,7 +101,7 @@
<ul> <ul>
{% for file in version.all_files %} {% for file in version.all_files %}
<li> <li>
{{ file_status_message(file, addon) }} {{ file_status_message(file) }}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

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

@ -17,7 +17,7 @@
</span> </span>
</td> </td>
<td class="file-status"> <td class="file-status">
{% for count, status in dev_files_status(version.all_files, addon) %} {% for count, status in dev_files_status(version.all_files) %}
<div> <div>
{# L10n: {0} is the number of files #} {# L10n: {0} is the number of files #}
{{ status }} ({{ ngettext('{0} file', '{0} files', count)|f(count) }}) {{ status }} ({{ ngettext('{0} file', '{0} files', count)|f(count) }})
@ -77,22 +77,19 @@
<a href="#" class="remove" data-version="{{ version.id }}" data-is-current="{{ (version == addon.current_version)|int }}">x</a> <a href="#" class="remove" data-version="{{ version.id }}" data-is-current="{{ (version == addon.current_version)|int }}">x</a>
</td> </td>
</tr> </tr>
{% set no_prelim = waffle.flag('no-prelim-review') %} {% set request_reviews=addon.can_request_review(disallow_preliminary_review=True) %}
{% set request_reviews=addon.can_request_review(no_prelim) %} {% set can_cancel=(not addon.is_disabled and addon.status==amo.STATUS_NOMINATED) %}
{% set can_cancel=(not addon.is_disabled and addon.is_under_review) %}
{% if full_info and check_addon_ownership(request, addon, dev=True) and (request_reviews or can_cancel) %} {% if full_info and check_addon_ownership(request, addon, dev=True) and (request_reviews or can_cancel) %}
<tr> <tr>
<td colspan="0" class="version-status-actions item-actions"> <td colspan="0" class="version-status-actions item-actions">
{% set req = {amo.STATUS_PUBLIC: _('Request Full Review'),
amo.STATUS_LITE: _('Request Preliminary Review')} %}
{% for status in request_reviews %} {% for status in request_reviews %}
<form method="post" <form method="post"
action="{{ url('devhub.request-review', addon.slug, status) }}" action="{{ url('devhub.request-review', addon.slug) }}"
{% if not addon.is_listed and status == amo.STATUS_PUBLIC %} {% if not addon.is_listed and status == amo.STATUS_PUBLIC %}
data-confirm="#modal-full-review" data-confirm="#modal-full-review"
{% endif %}> {% endif %}>
{{ csrf() }} {{ csrf() }}
<button class="link" type="submit">{{ req[status] }}</button> &middot; <button class="link" type="submit">{{ _('Request Full Review') }}</button> &middot;
</form> </form>
{% endfor %} {% endfor %}
{% if can_cancel %} {% if can_cancel %}
@ -364,23 +361,16 @@
{% endif %} {% endif %}
{% if not addon.is_disabled and addon.is_under_review %} {% if not addon.is_disabled and addon.status == amo.STATUS_NOMINATED %}
<div id="modal-cancel" class="modal"> <div id="modal-cancel" class="modal">
<form method="post" action="{{ url('devhub.addons.cancel', addon.slug) }}"> <form method="post" action="{{ url('devhub.addons.cancel', addon.slug) }}">
<h3>{{ _('Cancel Review Request') }}</h3> <h3>{{ _('Cancel Review Request') }}</h3>
<p> <p>
{% if addon.status == amo.STATUS_LITE_AND_NOMINATED %} {% trans %}
{% trans %}
Canceling your review request will leave your
add-on as preliminarily reviewed.
{% endtrans %}
{% else %}
{% trans %}
Canceling your review request will mark your add-on incomplete. Canceling your review request will mark your add-on incomplete.
If you do not complete your add-on after several days If you do not complete your add-on after several days
by re-requesting review, it will be deleted. by re-requesting review, it will be deleted.
{% endtrans %} {% endtrans %}
{% endif %}
</p> </p>
<p> <p>
{% trans %} {% trans %}

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

@ -163,41 +163,26 @@ class TestDevFilesStatus(TestCase):
def setUp(self): def setUp(self):
super(TestDevFilesStatus, self).setUp() super(TestDevFilesStatus, self).setUp()
self.addon = Addon.objects.create(type=1, status=amo.STATUS_UNREVIEWED) self.addon = Addon.objects.create(type=1, status=amo.STATUS_NOMINATED)
self.version = Version.objects.create(addon=self.addon) self.version = Version.objects.create(addon=self.addon)
self.file = File.objects.create(version=self.version, self.file = File.objects.create(version=self.version,
platform=amo.PLATFORM_ALL.id, platform=amo.PLATFORM_ALL.id,
status=amo.STATUS_UNREVIEWED) status=amo.STATUS_UNREVIEWED)
def expect(self, expected): def expect(self, expected):
cnt, msg = helpers.dev_files_status([self.file], self.addon)[0] cnt, msg = helpers.dev_files_status([self.file])[0]
assert cnt == 1 assert cnt == 1
assert msg == unicode(expected) assert msg == unicode(expected)
def test_unreviewed_lite(self):
self.addon.status = amo.STATUS_LITE
self.file.status = amo.STATUS_UNREVIEWED
self.expect(Addon.STATUS_CHOICES[amo.STATUS_UNREVIEWED])
def test_unreviewed_public(self): def test_unreviewed_public(self):
self.addon.status = amo.STATUS_PUBLIC self.addon.status = amo.STATUS_PUBLIC
self.file.status = amo.STATUS_UNREVIEWED self.file.status = amo.STATUS_UNREVIEWED
self.expect(Addon.STATUS_CHOICES[amo.STATUS_NOMINATED]) self.expect(File.STATUS_CHOICES[amo.STATUS_UNREVIEWED])
def test_unreviewed_nominated(self): def test_unreviewed_nominated(self):
self.addon.status = amo.STATUS_NOMINATED self.addon.status = amo.STATUS_NOMINATED
self.file.status = amo.STATUS_UNREVIEWED self.file.status = amo.STATUS_UNREVIEWED
self.expect(Addon.STATUS_CHOICES[amo.STATUS_NOMINATED]) self.expect(File.STATUS_CHOICES[amo.STATUS_UNREVIEWED])
def test_unreviewed_lite_and_nominated(self):
self.addon.status = amo.STATUS_LITE_AND_NOMINATED
self.file.status = amo.STATUS_UNREVIEWED
self.expect(Addon.STATUS_CHOICES[amo.STATUS_NOMINATED])
def test_reviewed_lite(self):
self.addon.status = amo.STATUS_LITE
self.file.status = amo.STATUS_LITE
self.expect(File.STATUS_CHOICES[amo.STATUS_LITE])
def test_reviewed_public(self): def test_reviewed_public(self):
self.addon.status = amo.STATUS_PUBLIC self.addon.status = amo.STATUS_PUBLIC

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

@ -681,10 +681,8 @@ class TestSubmitFile(TestCase):
@mock.patch('olympia.devhub.tasks.FileUpload.passed_all_validations', True) @mock.patch('olympia.devhub.tasks.FileUpload.passed_all_validations', True)
def test_file_passed_all_validations(self): def test_file_passed_all_validations(self):
upload = self.create_upload() upload = self.create_upload()
tasks.submit_file(self.addon.pk, upload.pk, tasks.submit_file(self.addon.pk, upload.pk)
disallow_preliminary_review=False) self.create_version_for_upload.assert_called_with(self.addon, upload)
self.create_version_for_upload.assert_called_with(
self.addon, upload, disallow_preliminary_review=False)
@mock.patch('olympia.devhub.tasks.FileUpload.passed_all_validations', @mock.patch('olympia.devhub.tasks.FileUpload.passed_all_validations',
False) False)

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

@ -669,7 +669,7 @@ class TestValidationAnnotatorListed(TestValidationAnnotatorBase):
self.file_1_1.update(status=amo.STATUS_UNREVIEWED) self.file_1_1.update(status=amo.STATUS_UNREVIEWED)
self.check_upload(self.file) self.check_upload(self.file)
# We can't prevent matching against prelim or beta versions # We can't prevent matching against beta versions
# until we change the file upload process to allow flagging # until we change the file upload process to allow flagging
# beta versions prior to validation. # beta versions prior to validation.
@ -681,7 +681,7 @@ class TestValidationAnnotatorListed(TestValidationAnnotatorBase):
self.check_file(self.file_1_1, self.file) self.check_file(self.file_1_1, self.file)
for status in amo.STATUS_UNREVIEWED, amo.STATUS_LITE, amo.STATUS_BETA: for status in amo.STATUS_UNREVIEWED, amo.STATUS_BETA:
self.validate_file.reset_mock() self.validate_file.reset_mock()
self.save_file.reset_mock() self.save_file.reset_mock()

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

@ -19,7 +19,6 @@ import waffle
from jingo.helpers import datetime as datetime_filter from jingo.helpers import datetime as datetime_filter
from PIL import Image from PIL import Image
from pyquery import PyQuery as pq from pyquery import PyQuery as pq
from waffle.testutils import override_flag
from olympia import amo, paypal, files from olympia import amo, paypal, files
from olympia.amo.tests import TestCase, version_factory from olympia.amo.tests import TestCase, version_factory
@ -852,8 +851,7 @@ class TestHome(TestCase):
def test_my_addons(self): def test_my_addons(self):
statuses = [(amo.STATUS_NOMINATED, amo.STATUS_UNREVIEWED), statuses = [(amo.STATUS_NOMINATED, amo.STATUS_UNREVIEWED),
(amo.STATUS_PUBLIC, amo.STATUS_UNREVIEWED), (amo.STATUS_PUBLIC, amo.STATUS_UNREVIEWED)]
(amo.STATUS_LITE, amo.STATUS_UNREVIEWED)]
for addon_status in statuses: for addon_status in statuses:
file = self.addon.latest_version.files.all()[0] file = self.addon.latest_version.files.all()[0]
@ -1336,8 +1334,6 @@ class TestSubmitStep2(TestCase):
assert response.status_code == 200 assert response.status_code == 200
doc = pq(response.content) doc = pq(response.content)
assert doc('.list-addon input#id_is_unlisted[type=checkbox]') assert doc('.list-addon input#id_is_unlisted[type=checkbox]')
# There also is a checkbox to select full review (side-load) or prelim.
assert doc('.list-addon input#id_is_sideload[type=checkbox]')
class TestSubmitStep3(TestSubmitBase): class TestSubmitStep3(TestSubmitBase):
@ -1412,7 +1408,7 @@ class TestSubmitStep3(TestSubmitBase):
'slug': 'unlisted-addon', 'slug': 'unlisted-addon',
'summary': 'summary'}) 'summary': 'summary'})
assert response.status_code == 302 assert response.status_code == 302
assert response.url.endswith(reverse('devhub.submit.7', assert response.url.endswith(reverse('devhub.submit.6',
args=['unlisted-addon'])) args=['unlisted-addon']))
# Unlisted addons don't need much info, and their queue is chosen # Unlisted addons don't need much info, and their queue is chosen
# automatically on step 2, so we skip steps 4, 5 and 6. We thus have no # automatically on step 2, so we skip steps 4, 5 and 6. We thus have no
@ -1722,11 +1718,11 @@ class TestSubmitStep4(TestSubmitBase):
assert self.get_step().step == 5 assert self.get_step().step == 5
class TestSubmitStep5_with_prelim(TestSubmitBase): class TestSubmitStep5(TestSubmitBase):
"""License submission.""" """License submission."""
def setUp(self): def setUp(self):
super(TestSubmitStep5_with_prelim, self).setUp() super(TestSubmitStep5, self).setUp()
SubmitStep.objects.create(addon_id=self.addon.id, step=5) SubmitStep.objects.create(addon_id=self.addon.id, step=5)
self.url = reverse('devhub.submit.5', args=['a3615']) self.url = reverse('devhub.submit.5', args=['a3615'])
self.next_step = reverse('devhub.submit.6', args=['a3615']) self.next_step = reverse('devhub.submit.6', args=['a3615'])
@ -1735,57 +1731,6 @@ class TestSubmitStep5_with_prelim(TestSubmitBase):
def test_get(self): def test_get(self):
assert self.client.get(self.url).status_code == 200 assert self.client.get(self.url).status_code == 200
def test_set_license(self):
r = self.client.post(self.url, {'builtin': 3})
self.assert3xx(r, self.next_step)
assert self.get_addon().current_version.license.builtin == 3
assert self.get_step().step == 6
log_items = ActivityLog.objects.for_addons(self.get_addon())
assert not log_items.filter(action=amo.LOG.CHANGE_LICENSE.id), (
"Initial license choice:6 needn't be logged.")
def test_license_error(self):
r = self.client.post(self.url, {'builtin': 4})
assert r.status_code == 200
self.assertFormError(r, 'license_form', 'builtin',
'Select a valid choice. 4 is not one of '
'the available choices.')
assert self.get_step().step == 5
def test_set_eula(self):
self.get_addon().update(eula=None, privacy_policy=None)
r = self.client.post(self.url, dict(builtin=3, has_eula=True,
eula='xxx'))
self.assert3xx(r, self.next_step)
assert unicode(self.get_addon().eula) == 'xxx'
assert self.get_step().step == 6
def test_set_eula_nomsg(self):
"""
You should not get punished with a 500 for not writing your EULA...
but perhaps you should feel shame for lying to us. This test does not
test for shame.
"""
self.get_addon().update(eula=None, privacy_policy=None)
r = self.client.post(self.url, dict(builtin=3, has_eula=True))
self.assert3xx(r, self.next_step)
assert self.get_step().step == 6
@override_flag('no-prelim-review', active=True)
class TestSubmitStep5_no_prelim(TestSubmitBase):
"""License submission."""
def setUp(self):
super(TestSubmitStep5_no_prelim, self).setUp()
SubmitStep.objects.create(addon_id=self.addon.id, step=5)
self.url = reverse('devhub.submit.5', args=['a3615'])
self.next_step = reverse('devhub.submit.7', args=['a3615'])
License.objects.create(builtin=3, on_form=True)
def test_get(self):
assert self.client.get(self.url).status_code == 200
def test_set_license(self): def test_set_license(self):
r = self.client.post(self.url, {'builtin': 3}) r = self.client.post(self.url, {'builtin': 3})
self.assert3xx(r, self.next_step) self.assert3xx(r, self.next_step)
@ -1844,62 +1789,7 @@ class TestSubmitStep6(TestSubmitBase):
def setUp(self): def setUp(self):
super(TestSubmitStep6, self).setUp() super(TestSubmitStep6, self).setUp()
SubmitStep.objects.create(addon_id=3615, step=6) self.url = reverse('devhub.submit.6', args=[self.addon.slug])
self.url = reverse('devhub.submit.6', args=['a3615'])
def test_get(self):
r = self.client.get(self.url)
assert r.status_code == 200
def test_require_review_type(self):
r = self.client.post(self.url, {'dummy': 'text'})
assert r.status_code == 200
self.assertFormError(r, 'review_type_form', 'review_type',
'A review type must be selected.')
def test_bad_review_type(self):
d = dict(review_type='jetsfool')
r = self.client.post(self.url, d)
assert r.status_code == 200
self.assertFormError(r, 'review_type_form', 'review_type',
'Select a valid choice. jetsfool is not one of '
'the available choices.')
def test_prelim_review(self):
d = dict(review_type=amo.STATUS_UNREVIEWED)
r = self.client.post(self.url, d)
assert r.status_code == 302
assert self.get_addon().status == amo.STATUS_UNREVIEWED
pytest.raises(SubmitStep.DoesNotExist, self.get_step)
def test_full_review(self):
self.get_version().update(nomination=None)
d = dict(review_type=amo.STATUS_NOMINATED)
r = self.client.post(self.url, d)
assert r.status_code == 302
addon = self.get_addon()
assert addon.status == amo.STATUS_NOMINATED
self.assertCloseToNow(self.get_version().nomination)
pytest.raises(SubmitStep.DoesNotExist, self.get_step)
def test_nomination_date_is_only_set_once(self):
# This was a regression, see bug 632191.
# Nominate:
r = self.client.post(self.url, dict(review_type=amo.STATUS_NOMINATED))
assert r.status_code == 302
nomdate = datetime.now() - timedelta(days=5)
self.get_version().update(nomination=nomdate, _signal=False)
# Update something else in the addon:
self.get_addon().update(slug='foobar')
assert self.get_version().nomination.timetuple()[0:5] == (
nomdate.timetuple()[0:5])
class TestSubmitStep7(TestSubmitBase):
def setUp(self):
super(TestSubmitStep7, self).setUp()
self.url = reverse('devhub.submit.7', args=[self.addon.slug])
@mock.patch.object(settings, 'SITE_URL', 'http://b.ro') @mock.patch.object(settings, 'SITE_URL', 'http://b.ro')
@mock.patch('olympia.devhub.tasks.send_welcome_email.delay') @mock.patch('olympia.devhub.tasks.send_welcome_email.delay')
@ -1949,7 +1839,7 @@ class TestSubmitStep7(TestSubmitBase):
@mock.patch('olympia.devhub.tasks.send_welcome_email.delay', new=mock.Mock) @mock.patch('olympia.devhub.tasks.send_welcome_email.delay', new=mock.Mock)
def test_finish_submitting_unlisted_addon(self): def test_finish_submitting_unlisted_addon(self):
self.addon.update(is_listed=False, status=amo.STATUS_UNREVIEWED) self.addon.update(is_listed=False, status=amo.STATUS_NOMINATED)
r = self.client.get(self.url) r = self.client.get(self.url)
assert r.status_code == 200 assert r.status_code == 200
@ -1984,7 +1874,7 @@ class TestSubmitStep7(TestSubmitBase):
# mac-only Add-on: # mac-only Add-on:
addon = Addon.objects.get(name__localized_string='Cooliris') addon = Addon.objects.get(name__localized_string='Cooliris')
addon.addonuser_set.create(user_id=55021) addon.addonuser_set.create(user_id=55021)
r = self.client.get(reverse('devhub.submit.7', args=[addon.slug])) r = self.client.get(reverse('devhub.submit.6', args=[addon.slug]))
assert r.status_code == 200 assert r.status_code == 200
next_steps = pq(r.content)('.done-next-steps li a') next_steps = pq(r.content)('.done-next-steps li a')
@ -1997,16 +1887,6 @@ class TestSubmitStep7(TestSubmitBase):
# edit listing of freshly submitted add-on... # edit listing of freshly submitted add-on...
assert next_steps.eq(1).attr('href') == addon.get_dev_url() assert next_steps.eq(1).attr('href') == addon.get_dev_url()
@mock.patch('olympia.devhub.tasks.send_welcome_email.delay', new=mock.Mock)
def test_finish_addon_for_prelim_review(self):
self.addon.update(status=amo.STATUS_UNREVIEWED)
response = self.client.get(self.url)
assert response.status_code == 200
doc = pq(response.content)
intro = doc('.addon-submission-process p').text().strip()
assert 'Preliminary Review' in intro, ('Unexpected intro: %s' % intro)
@mock.patch('olympia.devhub.tasks.send_welcome_email.delay', new=mock.Mock) @mock.patch('olympia.devhub.tasks.send_welcome_email.delay', new=mock.Mock)
def test_finish_addon_for_full_review(self): def test_finish_addon_for_full_review(self):
self.addon.update(status=amo.STATUS_NOMINATED) self.addon.update(status=amo.STATUS_NOMINATED)
@ -2035,7 +1915,7 @@ class TestSubmitStep7(TestSubmitBase):
def test_display_non_ascii_url(self): def test_display_non_ascii_url(self):
u = 'フォクすけといっしょ' u = 'フォクすけといっしょ'
self.addon.update(slug=u) self.addon.update(slug=u)
r = self.client.get(reverse('devhub.submit.7', args=[u])) r = self.client.get(reverse('devhub.submit.6', args=[u]))
assert r.status_code == 200 assert r.status_code == 200
# The meta charset will always be utf-8. # The meta charset will always be utf-8.
doc = pq(r.content.decode('utf-8')) doc = pq(r.content.decode('utf-8'))
@ -2056,7 +1936,7 @@ class TestResumeStep(TestSubmitBase):
def test_step_redirects(self): def test_step_redirects(self):
SubmitStep.objects.create(addon_id=3615, step=1) SubmitStep.objects.create(addon_id=3615, step=1)
for i in xrange(3, 7): for i in xrange(3, 6):
SubmitStep.objects.filter(addon=self.get_addon()).update(step=i) SubmitStep.objects.filter(addon=self.get_addon()).update(step=i)
r = self.client.get(self.url, follow=True) r = self.client.get(self.url, follow=True)
self.assert3xx(r, reverse('devhub.submit.%s' % i, self.assert3xx(r, reverse('devhub.submit.%s' % i,
@ -2098,7 +1978,7 @@ class TestSubmitSteps(TestCase):
def assert_linked(self, doc, numbers): def assert_linked(self, doc, numbers):
"""Check that the nth <li> in the steps list is a link.""" """Check that the nth <li> in the steps list is a link."""
lis = doc('.submit-addon-progress li') lis = doc('.submit-addon-progress li')
assert len(lis) == 7 assert len(lis) == 6
for idx, li in enumerate(lis): for idx, li in enumerate(lis):
links = pq(li)('a') links = pq(li)('a')
if (idx + 1) in numbers: if (idx + 1) in numbers:
@ -2117,25 +1997,25 @@ class TestSubmitSteps(TestCase):
r = self.client.get(reverse('devhub.submit.1')) r = self.client.get(reverse('devhub.submit.1'))
assert r.status_code == 200 assert r.status_code == 200
def test_on_step_6(self): def test_on_step_5(self):
# Hitting the step we're supposed to be on is a 200. # Hitting the step we're supposed to be on is a 200.
SubmitStep.objects.create(addon_id=3615, step=6) SubmitStep.objects.create(addon_id=3615, step=5)
r = self.client.get(reverse('devhub.submit.6', r = self.client.get(reverse('devhub.submit.5',
args=['a3615'])) args=['a3615']))
assert r.status_code == 200 assert r.status_code == 200
def test_skip_step_6(self): def test_skip_step_5(self):
# We get bounced back to step 3. # We get bounced back to step 3.
SubmitStep.objects.create(addon_id=3615, step=3) SubmitStep.objects.create(addon_id=3615, step=3)
r = self.client.get(reverse('devhub.submit.6', r = self.client.get(reverse('devhub.submit.5',
args=['a3615']), follow=True) args=['a3615']), follow=True)
self.assert3xx(r, reverse('devhub.submit.3', args=['a3615'])) self.assert3xx(r, reverse('devhub.submit.3', args=['a3615']))
def test_all_done(self): def test_all_done(self):
# There's no SubmitStep, so we must be done. # There's no SubmitStep, so we must be done.
r = self.client.get(reverse('devhub.submit.6', r = self.client.get(reverse('devhub.submit.5',
args=['a3615']), follow=True) args=['a3615']), follow=True)
self.assert3xx(r, reverse('devhub.submit.7', args=['a3615'])) self.assert3xx(r, reverse('devhub.submit.6', args=['a3615']))
def test_menu_step_1(self): def test_menu_step_1(self):
self.user.update(read_dev_agreement=None) self.user.update(read_dev_agreement=None)
@ -2156,51 +2036,32 @@ class TestSubmitSteps(TestCase):
self.assert_linked(doc, [3]) self.assert_linked(doc, [3])
self.assert_highlight(doc, 3) self.assert_highlight(doc, 3)
def test_menu_step_3_from_6(self): def test_menu_step_3_from_5(self):
SubmitStep.objects.create(addon_id=3615, step=6) SubmitStep.objects.create(addon_id=3615, step=5)
url = reverse('devhub.submit.3', args=['a3615']) url = reverse('devhub.submit.3', args=['a3615'])
doc = pq(self.client.get(url).content) doc = pq(self.client.get(url).content)
self.assert_linked(doc, [3, 4, 5, 6]) self.assert_linked(doc, [3, 4, 5])
self.assert_highlight(doc, 3) self.assert_highlight(doc, 3)
def test_menu_step_6(self): def test_menu_step_6(self):
SubmitStep.objects.create(addon_id=3615, step=6)
url = reverse('devhub.submit.6', args=['a3615']) url = reverse('devhub.submit.6', args=['a3615'])
doc = pq(self.client.get(url).content) doc = pq(self.client.get(url).content)
self.assert_linked(doc, [3, 4, 5, 6]) self.assert_linked(doc, [])
self.assert_highlight(doc, 6) self.assert_highlight(doc, 6)
def test_menu_step_7(self): def test_menu_step_6_unlisted(self):
url = reverse('devhub.submit.7', args=['a3615']) SubmitStep.objects.create(addon_id=3615, step=6)
doc = pq(self.client.get(url).content)
self.assert_linked(doc, [])
self.assert_highlight(doc, 7)
def test_menu_step_7_unlisted(self):
SubmitStep.objects.create(addon_id=3615, step=7)
Addon.objects.get(pk=3615).update(is_listed=False) Addon.objects.get(pk=3615).update(is_listed=False)
url = reverse('devhub.submit.7', args=['a3615']) url = reverse('devhub.submit.6', args=['a3615'])
doc = pq(self.client.get(url).content) doc = pq(self.client.get(url).content)
self.assert_linked(doc, []) # Last step: no previous step linked. self.assert_linked(doc, []) # Last step: no previous step linked.
# Skipped from step 3 to 7, as unlisted add-ons don't need listing # Skipped from step 3 to 6, as unlisted add-ons don't need listing
# information. Thus none of the steps from 4 to 6 should be there. # information. Thus none of the steps from 4 to 5 should be there.
# For reference, the steps that are with the "listed" class (instead of # For reference, the steps that are with the "listed" class (instead of
# "all") aren't displayed. # "all") aren't displayed.
assert len(doc('.submit-addon-progress li.all')) == 4 assert len(doc('.submit-addon-progress li.all')) == 4
# The step 7 is thus the 4th visible in the list. # The step 6 is thus the 4th visible in the list.
self.assert_highlight(doc, 7) # Current step is still the 7th. self.assert_highlight(doc, 6) # Current step is still the 6th.
@override_flag('no-prelim-review', active=True)
def test_menu_step_7_no_prelim(self):
SubmitStep.objects.create(addon_id=3615, step=7)
url = reverse('devhub.submit.7', args=['a3615'])
doc = pq(self.client.get(url).content)
self.assert_linked(doc, []) # Last step: no previous step linked.
# Skipped step 6, so we're one short, as no review selection.
assert (len(doc('.submit-addon-progress li.all')) +
len(doc('.submit-addon-progress li.listed'))) == 6
# The step 7 is thus the 6th visible in the list.
self.assert_highlight(doc, 7) # Current step is still the 7th.
class TestUpload(BaseUploadTest): class TestUpload(BaseUploadTest):
@ -2527,8 +2388,7 @@ class TestQueuePosition(UploadTest):
def test_in_queue(self): def test_in_queue(self):
statuses = [(amo.STATUS_NOMINATED, amo.STATUS_UNREVIEWED), statuses = [(amo.STATUS_NOMINATED, amo.STATUS_UNREVIEWED),
(amo.STATUS_PUBLIC, amo.STATUS_UNREVIEWED), (amo.STATUS_PUBLIC, amo.STATUS_UNREVIEWED)]
(amo.STATUS_LITE, amo.STATUS_UNREVIEWED)]
for addon_status in statuses: for addon_status in statuses:
self.addon.status = addon_status[0] self.addon.status = addon_status[0]
@ -2561,6 +2421,7 @@ class TestVersionAddFile(UploadTest):
version_files = self.version.files.all()[0] version_files = self.version.files.all()[0]
version_files.update(platform=amo.PLATFORM_LINUX.id, version_files.update(platform=amo.PLATFORM_LINUX.id,
status=amo.STATUS_UNREVIEWED) status=amo.STATUS_UNREVIEWED)
self.addon.update(status=amo.STATUS_NOMINATED)
# We need to clear the cached properties for platform change above. # We need to clear the cached properties for platform change above.
del self.version.supported_platforms del self.version.supported_platforms
del self.version.all_files del self.version.all_files
@ -2760,60 +2621,12 @@ class TestVersionAddFile(UploadTest):
assert response.status_code == 400 assert response.status_code == 400
assert 'source' in json.loads(response.content) assert 'source' in json.loads(response.content)
@mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_sideload_fail_validation(self, mock_sign_file):
"""Sideloadable unlisted addons are also auto signed/reviewed."""
self.version.all_files[0].update(status=amo.STATUS_PUBLIC)
self.addon.update(is_listed=False, status=amo.STATUS_PUBLIC)
# Make sure the file has validation warnings or errors.
self.upload.update(
validation='{"notices": 2, "errors": 0, "messages": [],'
' "metadata": {}, "warnings": 1,'
' "signing_summary": {"trivial": 1, "low": 1,'
' "medium": 0, "high": 0},'
' "passed_auto_validation": 1}')
self.post()
file_ = File.objects.latest()
# Status is changed to fully reviewed and the file is signed.
assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called
# There is a log for that unlisted file signature (with failed
# validation).
log = ActivityLog.objects.order_by('pk').last()
expected = amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_FAILED.id
assert log.action == expected
@mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_sideload_pass_validation(self, mock_sign_file):
"""Sideloadable unlisted addons are also auto signed/reviewed."""
self.version.all_files[0].update(status=amo.STATUS_PUBLIC)
self.addon.update(is_listed=False, status=amo.STATUS_PUBLIC)
# Make sure the file has no validation signing related messages.
self.upload.update(
validation='{"notices": 2, "errors": 0, "messages": [],'
' "metadata": {}, "warnings": 1,'
' "signing_summary": {"trivial": 1, "low": 0,'
' "medium": 0, "high": 0},'
' "passed_auto_validation": 1}')
self.post()
file_ = File.objects.latest()
# Status is changed to fully reviewed and the file is signed.
assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called
# There is a log for that unlisted file signature (with failed
# validation).
log = ActivityLog.objects.order_by('pk').last()
expected = amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_PASSED.id
assert log.action == expected
@mock.patch('olympia.editors.helpers.sign_file') @mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_fail_validation(self, mock_sign_file): def test_unlisted_addon_fail_validation(self, mock_sign_file):
"""Files that fail validation are also auto signed/reviewed.""" """Files that fail validation are also auto signed/reviewed."""
self.addon.update( self.version.all_files[0].update(status=amo.STATUS_PUBLIC)
is_listed=False, status=amo.STATUS_LITE) self.addon.update(is_listed=False, status=amo.STATUS_PUBLIC)
assert self.addon.status == amo.STATUS_LITE # Preliminary reviewed. assert self.addon.status == amo.STATUS_PUBLIC
# Make sure the file has validation warnings or errors. # Make sure the file has validation warnings or errors.
self.upload.update( self.upload.update(
validation='{"notices": 2, "errors": 0, "messages": [],' validation='{"notices": 2, "errors": 0, "messages": [],'
@ -2823,68 +2636,18 @@ class TestVersionAddFile(UploadTest):
' "passed_auto_validation": 1}') ' "passed_auto_validation": 1}')
self.post() self.post()
file_ = File.objects.latest() file_ = File.objects.latest()
# Status is changed to preliminary reviewed and the file is signed. # Status is changed to reviewed and the file is signed.
assert self.addon.status == amo.STATUS_LITE assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_LITE assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called assert mock_sign_file.called
# There is a log for that unlisted file signature (with failed # There is a log for that unlisted file signature (with failed
# validation). # validation).
log = ActivityLog.objects.order_by('pk').last() log = ActivityLog.objects.order_by('pk').last()
assert log.action == amo.LOG.UNLISTED_SIGNED_VALIDATION_FAILED.id expected = amo.LOG.UNLISTED_SIGNED_VALIDATION_FAILED.id
assert log.action == expected
@mock.patch('olympia.editors.helpers.sign_file') @mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_pass_validation(self, mock_sign_file): def test_unlisted_addon_pass_validation(self, mock_sign_file):
"""Files that pass validation are automatically signed/reviewed."""
self.addon.update(
is_listed=False, status=amo.STATUS_LITE)
# Make sure the file has no validation signing related messages.
self.upload.update(
validation='{"notices": 2, "errors": 0, "messages": [],'
' "metadata": {}, "warnings": 1,'
' "signing_summary": {"trivial": 1, "low": 0,'
' "medium": 0, "high": 0},'
' "passed_auto_validation": 1}')
assert self.addon.status == amo.STATUS_LITE # Preliminary reviewed.
self.post()
file_ = File.objects.latest()
# Status is changed to preliminary reviewed and the file is signed.
assert self.addon.status == amo.STATUS_LITE
assert file_.status == amo.STATUS_LITE
assert mock_sign_file.called
# There is a log for that unlisted file signature (with passed
# validation).
log = ActivityLog.objects.order_by('pk').last()
assert log.action == amo.LOG.UNLISTED_SIGNED_VALIDATION_PASSED.id
@override_flag('no-prelim-review', active=True)
@mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_fail_validation_no_prelim(self, mock_sign_file):
"""Files that fail validation are also auto signed/reviewed."""
self.version.all_files[0].update(status=amo.STATUS_PUBLIC)
self.addon.update(is_listed=False, status=amo.STATUS_PUBLIC)
assert self.addon.status == amo.STATUS_PUBLIC
# Make sure the file has validation warnings or errors.
self.upload.update(
validation='{"notices": 2, "errors": 0, "messages": [],'
' "metadata": {}, "warnings": 1,'
' "signing_summary": {"trivial": 1, "low": 1,'
' "medium": 0, "high": 0},'
' "passed_auto_validation": 1}')
self.post()
file_ = File.objects.latest()
# Status is changed to reviewed and the file is signed.
assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called
# There is a log for that unlisted file signature (with failed
# validation).
log = ActivityLog.objects.order_by('pk').last()
expected = amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_FAILED.id
assert log.action == expected
@override_flag('no-prelim-review', active=True)
@mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_pass_validation_noprelim(self, mock_sign_file):
"""Files that pass validation are automatically signed/reviewed.""" """Files that pass validation are automatically signed/reviewed."""
self.version.all_files[0].update(status=amo.STATUS_PUBLIC) self.version.all_files[0].update(status=amo.STATUS_PUBLIC)
self.addon.update(is_listed=False, status=amo.STATUS_PUBLIC) self.addon.update(is_listed=False, status=amo.STATUS_PUBLIC)
@ -2905,7 +2668,7 @@ class TestVersionAddFile(UploadTest):
# There is a log for that unlisted file signature (with passed # There is a log for that unlisted file signature (with passed
# validation). # validation).
log = ActivityLog.objects.order_by('pk').last() log = ActivityLog.objects.order_by('pk').last()
expected = amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_PASSED.id expected = amo.LOG.UNLISTED_SIGNED_VALIDATION_PASSED.id
assert log.action == expected assert log.action == expected
@mock.patch('olympia.devhub.views.sign_file') @mock.patch('olympia.devhub.views.sign_file')
@ -3071,8 +2834,7 @@ class TestAddVersion(AddVersionTest):
# versions has been deleted either. # versions has been deleted either.
self.version.update(version='0.1') self.version.update(version='0.1')
self.version.delete() self.version.delete()
r = self.post(expected_status=400, r = self.post(expected_status=400)
nomination_type=amo.STATUS_NOMINATED)
assert_json_error( assert_json_error(
r, None, 'Version 0.1 already exists, or was uploaded before.') r, None, 'Version 0.1 already exists, or was uploaded before.')
@ -3083,8 +2845,7 @@ class TestAddVersion(AddVersionTest):
reverse('devhub.versions.edit', reverse('devhub.versions.edit',
args=[self.addon.slug, version.id])) args=[self.addon.slug, version.id]))
@override_flag('no-prelim-review', active=True) def test_incomplete_addon_now_nominated(self):
def test_incomplete_addon_now_nominated_when_no_prelim(self):
"""Uploading a new version for an incomplete addon should set it to """Uploading a new version for an incomplete addon should set it to
nominated.""" nominated."""
self.version.delete() self.version.delete()
@ -3147,62 +2908,12 @@ class TestAddVersion(AddVersionTest):
f = File.objects.latest() f = File.objects.latest()
assert f.status != amo.STATUS_BETA assert f.status != amo.STATUS_BETA
@mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_sideload_fail_validation(self, mock_sign_file):
"""Sideloadable unlisted addons also get auto signed/reviewed."""
assert self.addon.status == amo.STATUS_PUBLIC # Fully reviewed.
self.addon.update(is_listed=False)
# Make sure the file has validation warnings or errors.
self.upload.update(
validation=json.dumps({
"notices": 2, "errors": 0, "messages": [],
"metadata": {}, "warnings": 1,
"signing_summary": {"trivial": 1, "low": 1,
"medium": 0, "high": 0},
"passed_auto_validation": 0}))
self.post()
file_ = File.objects.latest()
# Status is changed to fully reviewed and the file is signed.
assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called
# There is a log for that unlisted file signature (with failed
# validation).
log = ActivityLog.objects.order_by('pk').last()
expected = amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_FAILED.id
assert log.action == expected
@mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_sideload_pass_validation(self, mock_sign_file):
"""Sideloadable unlisted addons also get auto signed/reviewed."""
assert self.addon.status == amo.STATUS_PUBLIC # Fully reviewed.
self.addon.update(is_listed=False)
# Make sure the file has no validation warnings nor errors.
self.upload.update(
validation=json.dumps({
"notices": 2, "errors": 0, "messages": [],
"metadata": {}, "warnings": 1,
"signing_summary": {"trivial": 1, "low": 0,
"medium": 0, "high": 0},
"passed_auto_validation": 1}))
self.post()
file_ = File.objects.latest()
# Status is changed to fully reviewed and the file is signed.
assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called
# There is a log for that unlisted file signature (with failed
# validation).
log = ActivityLog.objects.order_by('pk').last()
expected = amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_PASSED.id
assert log.action == expected
@mock.patch('olympia.editors.helpers.sign_file') @mock.patch('olympia.editors.helpers.sign_file')
def test_unlisted_addon_fail_validation(self, mock_sign_file): def test_unlisted_addon_fail_validation(self, mock_sign_file):
"""Files that fail validation are also auto signed/reviewed.""" """Files that fail validation are also auto signed/reviewed."""
self.addon.update( self.addon.update(
is_listed=False, status=amo.STATUS_LITE) is_listed=False, status=amo.STATUS_PUBLIC)
assert self.addon.status == amo.STATUS_LITE # Preliminary reviewed. assert self.addon.status == amo.STATUS_PUBLIC
# Make sure the file has validation warnings or errors. # Make sure the file has validation warnings or errors.
self.upload.update( self.upload.update(
validation=json.dumps({ validation=json.dumps({
@ -3213,9 +2924,9 @@ class TestAddVersion(AddVersionTest):
"passed_auto_validation": 0})) "passed_auto_validation": 0}))
self.post() self.post()
file_ = File.objects.latest() file_ = File.objects.latest()
# Status is changed to preliminary reviewed and the file is signed. # Status is changed to reviewed and the file is signed.
assert self.addon.status == amo.STATUS_LITE assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_LITE assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called assert mock_sign_file.called
# There is a log for that unlisted file signature (with failed # There is a log for that unlisted file signature (with failed
# validation). # validation).
@ -3226,7 +2937,7 @@ class TestAddVersion(AddVersionTest):
def test_unlisted_addon_pass_validation(self, mock_sign_file): def test_unlisted_addon_pass_validation(self, mock_sign_file):
"""Files that pass validation are automatically signed/reviewed.""" """Files that pass validation are automatically signed/reviewed."""
self.addon.update( self.addon.update(
is_listed=False, status=amo.STATUS_LITE) is_listed=False, status=amo.STATUS_PUBLIC)
# Make sure the file has no validation warnings nor errors. # Make sure the file has no validation warnings nor errors.
self.upload.update( self.upload.update(
validation=json.dumps({ validation=json.dumps({
@ -3235,12 +2946,12 @@ class TestAddVersion(AddVersionTest):
"signing_summary": {"trivial": 1, "low": 0, "signing_summary": {"trivial": 1, "low": 0,
"medium": 0, "high": 0}, "medium": 0, "high": 0},
"passed_auto_validation": 1})) "passed_auto_validation": 1}))
assert self.addon.status == amo.STATUS_LITE # Preliminary reviewed. assert self.addon.status == amo.STATUS_PUBLIC
self.post() self.post()
file_ = File.objects.latest() file_ = File.objects.latest()
# Status is changed to preliminary reviewed and the file is signed. # Status is changed to reviewed and the file is signed.
assert self.addon.status == amo.STATUS_LITE assert self.addon.status == amo.STATUS_PUBLIC
assert file_.status == amo.STATUS_LITE assert file_.status == amo.STATUS_PUBLIC
assert mock_sign_file.called assert mock_sign_file.called
# There is a log for that unlisted file signature (with passed # There is a log for that unlisted file signature (with passed
# validation). # validation).
@ -3428,10 +3139,10 @@ class TestVersionXSS(UploadTest):
class UploadAddon(object): class UploadAddon(object):
def post(self, supported_platforms=[amo.PLATFORM_ALL], expect_errors=False, def post(self, supported_platforms=[amo.PLATFORM_ALL], expect_errors=False,
source=None, is_listed=True, is_sideload=False, status_code=200): source=None, is_listed=True, status_code=200):
d = dict(upload=self.upload.uuid.hex, source=source, d = dict(upload=self.upload.uuid.hex, source=source,
supported_platforms=[p.id for p in supported_platforms], supported_platforms=[p.id for p in supported_platforms],
is_unlisted=not is_listed, is_sideload=is_sideload) is_unlisted=not is_listed)
r = self.client.post(self.url, d, follow=True) r = self.client.post(self.url, d, follow=True)
assert r.status_code == status_code assert r.status_code == status_code
if not expect_errors: if not expect_errors:
@ -3514,7 +3225,7 @@ class TestCreateAddon(BaseUploadTest, UploadAddon, TestCase):
self.post(is_listed=False) self.post(is_listed=False)
addon = Addon.with_unlisted.get() addon = Addon.with_unlisted.get()
assert not addon.is_listed assert not addon.is_listed
assert addon.status == amo.STATUS_LITE # Automatic signing. assert addon.status == amo.STATUS_PUBLIC
assert mock_sign_file.called assert mock_sign_file.called
@mock.patch('olympia.editors.helpers.sign_file') @mock.patch('olympia.editors.helpers.sign_file')
@ -3532,56 +3243,6 @@ class TestCreateAddon(BaseUploadTest, UploadAddon, TestCase):
self.post(is_listed=False) self.post(is_listed=False)
addon = Addon.with_unlisted.get() addon = Addon.with_unlisted.get()
assert not addon.is_listed assert not addon.is_listed
assert addon.status == amo.STATUS_LITE # Prelim review.
assert mock_sign_file.called
@override_flag('no-prelim-review', active=True)
@mock.patch('olympia.editors.helpers.sign_file')
def test_success_unlisted_no_prelim(self, mock_sign_file):
"""Sign automatically."""
assert Addon.with_unlisted.count() == 0
# No validation errors or warning.
self.upload = self.get_upload(
'extension.xpi',
validation=json.dumps(dict(errors=0, warnings=0, notices=2,
metadata={}, messages=[],
signing_summary={
'trivial': 1, 'low': 0, 'medium': 0,
'high': 0},
passed_auto_validation=True
)))
self.post(is_listed=False)
addon = Addon.with_unlisted.get()
assert not addon.is_listed
assert addon.status == amo.STATUS_PUBLIC # Automatic signing.
assert mock_sign_file.called
@override_flag('no-prelim-review', active=True)
@mock.patch('olympia.editors.helpers.sign_file')
def test_success_unlisted_fail_validation_no_prelim(self, mock_sign_file):
assert Addon.with_unlisted.count() == 0
self.upload = self.get_upload(
'extension.xpi',
validation=json.dumps(dict(errors=0, warnings=0, notices=2,
metadata={}, messages=[],
signing_summary={
'trivial': 0, 'low': 1, 'medium': 0,
'high': 0},
passed_auto_validation=False
)))
self.post(is_listed=False)
addon = Addon.with_unlisted.get()
assert not addon.is_listed
assert addon.status == amo.STATUS_PUBLIC
assert mock_sign_file.called
@mock.patch('olympia.editors.helpers.sign_file')
def test_success_unlisted_sideload(self, mock_sign_file):
assert Addon.with_unlisted.count() == 0
self.post(is_listed=False, is_sideload=True)
addon = Addon.with_unlisted.get()
assert not addon.is_listed
# Full review for sideload addons.
assert addon.status == amo.STATUS_PUBLIC assert addon.status == amo.STATUS_PUBLIC
assert mock_sign_file.called assert mock_sign_file.called
@ -3663,10 +3324,8 @@ class TestRequestReview(TestCase):
self.file = File.objects.create(version=self.version, self.file = File.objects.create(version=self.version,
platform=amo.PLATFORM_ALL.id) platform=amo.PLATFORM_ALL.id)
self.redirect_url = self.addon.get_dev_url('versions') self.redirect_url = self.addon.get_dev_url('versions')
self.lite_url = reverse('devhub.request-review',
args=[self.addon.slug, amo.STATUS_LITE])
self.public_url = reverse('devhub.request-review', self.public_url = reverse('devhub.request-review',
args=[self.addon.slug, amo.STATUS_PUBLIC]) args=[self.addon.slug])
assert self.client.login(username='admin@mozilla.com', assert self.client.login(username='admin@mozilla.com',
password='password') password='password')
@ -3686,40 +3345,8 @@ class TestRequestReview(TestCase):
r = self.client.post(url) r = self.client.post(url)
assert r.status_code == 400 assert r.status_code == 400
def test_404(self):
bad_url = self.public_url.replace(str(amo.STATUS_PUBLIC), '0')
assert self.client.post(bad_url).status_code == 404
def test_public(self): def test_public(self):
self.addon.update(status=amo.STATUS_PUBLIC) self.addon.update(status=amo.STATUS_PUBLIC)
self.check_400(self.lite_url)
self.check_400(self.public_url)
def test_disabled_by_user_to_lite(self):
self.addon.update(disabled_by_user=True)
self.check_400(self.lite_url)
def test_disabled_by_admin(self):
self.addon.update(status=amo.STATUS_DISABLED)
self.check_400(self.lite_url)
def test_lite_to_lite(self):
self.addon.update(status=amo.STATUS_LITE)
self.check_400(self.lite_url)
def test_lite_to_public(self):
assert self.version.nomination is None
self.check(amo.STATUS_LITE, self.public_url,
amo.STATUS_LITE_AND_NOMINATED)
self.assertCloseToNow(self.get_version().nomination)
def test_lite_and_nominated_to_public(self):
self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED)
self.check_400(self.public_url)
def test_lite_and_nominated(self):
self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED)
self.check_400(self.lite_url)
self.check_400(self.public_url) self.check_400(self.public_url)
def test_renominate_for_full_review(self): def test_renominate_for_full_review(self):
@ -3736,14 +3363,14 @@ class TestRequestReview(TestCase):
def test_renomination_doesnt_reset_nomination_date(self): def test_renomination_doesnt_reset_nomination_date(self):
# Nominate: # Nominate:
self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED) self.addon.update(status=amo.STATUS_NOMINATED)
# Pretend it was nominated in the past: # Pretend it was nominated in the past:
orig_date = datetime.now() - timedelta(days=30) orig_date = datetime.now() - timedelta(days=30)
self.version.update(nomination=orig_date, _signal=False) self.version.update(nomination=orig_date, _signal=False)
# Reject it: # Reject it:
self.addon.update(status=amo.STATUS_NULL) self.addon.update(status=amo.STATUS_NULL)
# Re-nominate: # Re-nominate:
self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED) self.addon.update(status=amo.STATUS_NOMINATED)
assert self.get_version().nomination.timetuple()[0:5] == ( assert self.get_version().nomination.timetuple()[0:5] == (
orig_date.timetuple()[0:5]) orig_date.timetuple()[0:5])

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

@ -11,7 +11,6 @@ from django.test.utils import override_settings
import mock import mock
from PIL import Image from PIL import Image
from pyquery import PyQuery as pq from pyquery import PyQuery as pq
from waffle.testutils import override_flag
from olympia import amo from olympia import amo
from olympia.amo.tests import TestCase from olympia.amo.tests import TestCase
@ -504,14 +503,12 @@ class TestEditBasic(TestEdit):
activity_url) activity_url)
assert doc('.view-stats').length == 1 assert doc('.view-stats').length == 1
@override_flag('no-prelim-review', active=True)
def test_not_experimental_flag(self): def test_not_experimental_flag(self):
r = self.client.get(self.url) r = self.client.get(self.url)
doc = pq(r.content) doc = pq(r.content)
assert doc('#experimental-edit').text() == ( assert doc('#experimental-edit').text() == (
'This add-on is ready for general use.') 'This add-on is ready for general use.')
@override_flag('no-prelim-review', active=True)
def test_experimental_flag(self): def test_experimental_flag(self):
self.get_addon().update(is_experimental=True) self.get_addon().update(is_experimental=True)
r = self.client.get(self.url) r = self.client.get(self.url)
@ -519,12 +516,6 @@ class TestEditBasic(TestEdit):
assert doc('#experimental-edit').text() == ( assert doc('#experimental-edit').text() == (
'This add-on is experimental.') 'This add-on is experimental.')
def test_experimental_flag_hidden(self):
# Shouldn't see anything with the waffle off.
r = self.client.get(self.url)
doc = pq(r.content)
assert not doc('#experimental-edit')
def get_l10n_urls(self): def get_l10n_urls(self):
paths = ('devhub.addons.edit', 'devhub.addons.profile', paths = ('devhub.addons.edit', 'devhub.addons.profile',
'devhub.addons.owner') 'devhub.addons.owner')
@ -1236,8 +1227,8 @@ class TestEditTechnical(TestEdit):
def test_dependencies_no_add_unreviewed_persona(self): def test_dependencies_no_add_unreviewed_persona(self):
"""Ensure that unreviewed Personas cannot be made as dependencies.""" """Ensure that unreviewed Personas cannot be made as dependencies."""
addon = Addon.objects.get(id=15663) addon = Addon.objects.get(id=15663)
addon.update(status=amo.STATUS_UNREVIEWED) addon.update(status=amo.STATUS_PENDING)
assert addon.status == amo.STATUS_UNREVIEWED assert addon.status == amo.STATUS_PENDING
assert addon not in list(Addon.objects.reviewed()) assert addon not in list(Addon.objects.reviewed())
d = self.dep_formset({'dependent_addon': addon.id}) d = self.dep_formset({'dependent_addon': addon.id})
r = self.client.post(self.technical_edit_url, d) r = self.client.post(self.technical_edit_url, d)

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

@ -350,21 +350,9 @@ class TestValidateAddon(TestCase):
self.client.post(self.url, {'upload': data}) self.client.post(self.url, {'upload': data})
# Make sure it was called with listed=False. # Make sure it was called with listed=False.
assert not validate_mock.call_args[1]['listed'] assert not validate_mock.call_args[1]['listed']
# Automated signing enabled for unlisted, non-sideload add-ons. # Automated signing enabled for unlisted add-ons.
assert FileUpload.objects.get().automated_signing is True assert FileUpload.objects.get().automated_signing is True
@mock.patch('validator.validate.validate')
def test_upload_sideload_addon(self, validate_mock):
"""Sideload addons are validated as "self-hosted" addons."""
validate_mock.return_value = json.dumps(amo.VALIDATOR_SKELETON_RESULTS)
self.url = reverse('devhub.upload_sideload')
data = open(get_image_path('animated.png'), 'rb')
self.client.post(self.url, {'upload': data})
# Make sure it was called with listed=False.
assert not validate_mock.call_args[1]['listed']
# No automated signing for sideload add-ons.
assert FileUpload.objects.get().automated_signing is False
class TestUploadURLs(TestCase): class TestUploadURLs(TestCase):
fixtures = ('base/users',) fixtures = ('base/users',)
@ -427,9 +415,6 @@ class TestUploadURLs(TestCase):
self.upload('devhub.standalone_upload_unlisted'), self.upload('devhub.standalone_upload_unlisted'),
self.expect_validation(listed=False, automated_signing=True) self.expect_validation(listed=False, automated_signing=True)
self.upload('devhub.standalone_upload_sideload'),
self.expect_validation(listed=False, automated_signing=False)
def test_upload_submit(self): def test_upload_submit(self):
"""Test that the add-on creation upload URLs result in file uploads """Test that the add-on creation upload URLs result in file uploads
with the correct flags.""" with the correct flags."""
@ -439,9 +424,6 @@ class TestUploadURLs(TestCase):
self.upload('devhub.upload_unlisted'), self.upload('devhub.upload_unlisted'),
self.expect_validation(listed=False, automated_signing=True) self.expect_validation(listed=False, automated_signing=True)
self.upload('devhub.upload_sideload'),
self.expect_validation(listed=False, automated_signing=False)
def test_upload_addon_version(self): def test_upload_addon_version(self):
"""Test that the add-on update upload URLs result in file uploads """Test that the add-on update upload URLs result in file uploads
with the correct flags.""" with the correct flags."""
@ -449,9 +431,6 @@ class TestUploadURLs(TestCase):
self.upload_addon(listed=True, status=status) self.upload_addon(listed=True, status=status)
self.expect_validation(listed=True, automated_signing=False) self.expect_validation(listed=True, automated_signing=False)
self.upload_addon(listed=False, status=amo.STATUS_LITE)
self.expect_validation(listed=False, automated_signing=True)
self.upload_addon(listed=False, status=amo.STATUS_PUBLIC) self.upload_addon(listed=False, status=amo.STATUS_PUBLIC)
self.expect_validation(listed=False, automated_signing=True) self.expect_validation(listed=False, automated_signing=True)

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

@ -2,7 +2,6 @@ import re
import mock import mock
from pyquery import PyQuery as pq from pyquery import PyQuery as pq
from waffle.testutils import override_flag
from django.core.files import temp from django.core.files import temp
@ -92,7 +91,7 @@ class TestVersion(TestCase):
def test_delete_message_if_bits_are_messy(self): def test_delete_message_if_bits_are_messy(self):
"""Make sure we warn krupas of the pain they will feel.""" """Make sure we warn krupas of the pain they will feel."""
self.addon.status = amo.STATUS_UNREVIEWED self.addon.status = amo.STATUS_NOMINATED
self.addon.save() self.addon.save()
r = self.client.get(self.url) r = self.client.get(self.url)
@ -122,7 +121,7 @@ class TestVersion(TestCase):
action=amo.LOG.DELETE_VERSION.id).count() == 1 action=amo.LOG.DELETE_VERSION.id).count() == 1
def test_delete_version_then_detail(self): def test_delete_version_then_detail(self):
version, file = self._extra_version_and_file(amo.STATUS_LITE) version, file = self._extra_version_and_file(amo.STATUS_PUBLIC)
self.client.post(self.delete_url, self.delete_data) self.client.post(self.delete_url, self.delete_data)
res = self.client.get(reverse('addons.detail', args=[self.addon.slug])) res = self.client.get(reverse('addons.detail', args=[self.addon.slug]))
assert res.status_code == 200 assert res.status_code == 200
@ -151,7 +150,7 @@ class TestVersion(TestCase):
def test_reenable_version(self): def test_reenable_version(self):
Version.objects.get(pk=81551).all_files[0].update( Version.objects.get(pk=81551).all_files[0].update(
status=amo.STATUS_DISABLED, original_status=amo.STATUS_LITE) status=amo.STATUS_DISABLED, original_status=amo.STATUS_PUBLIC)
self.reenable_url = reverse('devhub.versions.reenable', args=['a3615']) self.reenable_url = reverse('devhub.versions.reenable', args=['a3615'])
response = self.client.post( response = self.client.post(
self.reenable_url, self.delete_data, follow=True) self.reenable_url, self.delete_data, follow=True)
@ -401,7 +400,7 @@ class TestVersion(TestCase):
def test_cancel_wrong_status(self): def test_cancel_wrong_status(self):
cancel_url = reverse('devhub.addons.cancel', args=['a3615']) cancel_url = reverse('devhub.addons.cancel', args=['a3615'])
for status in Addon.STATUS_CHOICES: for status in Addon.STATUS_CHOICES:
if status in amo.UNDER_REVIEW_STATUSES + (amo.STATUS_DELETED,): if status in (amo.STATUS_NOMINATED, amo.STATUS_DELETED):
continue continue
self.addon.update(status=status) self.addon.update(status=status)
@ -410,14 +409,9 @@ class TestVersion(TestCase):
def test_cancel(self): def test_cancel(self):
cancel_url = reverse('devhub.addons.cancel', args=['a3615']) cancel_url = reverse('devhub.addons.cancel', args=['a3615'])
self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED) self.addon.update(status=amo.STATUS_NOMINATED)
self.client.post(cancel_url) self.client.post(cancel_url)
assert Addon.objects.get(id=3615).status == amo.STATUS_LITE assert Addon.objects.get(id=3615).status == amo.STATUS_NULL
for status in (amo.STATUS_UNREVIEWED, amo.STATUS_NOMINATED):
self.addon.update(status=status)
self.client.post(cancel_url)
assert Addon.objects.get(id=3615).status == amo.STATUS_NULL
def test_not_cancel(self): def test_not_cancel(self):
self.client.logout() self.client.logout()
@ -429,7 +423,7 @@ class TestVersion(TestCase):
def test_cancel_button(self): def test_cancel_button(self):
for status in Addon.STATUS_CHOICES: for status in Addon.STATUS_CHOICES:
if status not in amo.UNDER_REVIEW_STATUSES: if status != amo.STATUS_NOMINATED:
continue continue
self.addon.update(status=status) self.addon.update(status=status)
@ -440,23 +434,16 @@ class TestVersion(TestCase):
def test_not_cancel_button(self): def test_not_cancel_button(self):
for status in Addon.STATUS_CHOICES: for status in Addon.STATUS_CHOICES:
if status in amo.UNDER_REVIEW_STATUSES: if status == amo.STATUS_NOMINATED:
continue continue
self.addon.update(status=status) self.addon.update(status=status)
res = self.client.get(self.url) res = self.client.get(self.url)
doc = pq(res.content) doc = pq(res.content)
assert not doc('#cancel-review') assert not doc('#cancel-review'), status
assert not doc('#modal-cancel') assert not doc('#modal-cancel'), status
def test_incomplete_request_review(self): def test_incomplete_request_review(self):
self.addon.update(status=amo.STATUS_NULL)
doc = pq(self.client.get(self.url).content)
buttons = doc('.version-status-actions form button').text()
assert buttons == 'Request Preliminary Review Request Full Review'
@override_flag('no-prelim-review', active=True)
def test_incomplete_request_review_no_prelim(self):
self.addon.update(status=amo.STATUS_NULL) self.addon.update(status=amo.STATUS_NULL)
doc = pq(self.client.get(self.url).content) doc = pq(self.client.get(self.url).content)
buttons = doc('.version-status-actions form button').text() buttons = doc('.version-status-actions form button').text()

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

@ -14,12 +14,11 @@ PACKAGE_NAME = '(?P<package_name>[_\w]+)'
# These will all start with /addon/<addon_id>/submit/ # These will all start with /addon/<addon_id>/submit/
submit_patterns = patterns( submit_patterns = patterns(
'', '',
url('^$', lambda r, addon_id: redirect('devhub.submit.7', addon_id)), url('^$', lambda r, addon_id: redirect('devhub.submit.6', addon_id)),
url('^3$', views.submit_describe, name='devhub.submit.3'), url('^3$', views.submit_describe, name='devhub.submit.3'),
url('^4$', views.submit_media, name='devhub.submit.4'), url('^4$', views.submit_media, name='devhub.submit.4'),
url('^5$', views.submit_license, name='devhub.submit.5'), url('^5$', views.submit_license, name='devhub.submit.5'),
url('^6$', views.submit_select_review, name='devhub.submit.6'), url('^6$', views.submit_done, name='devhub.submit.6'),
url('^7$', views.submit_done, name='devhub.submit.7'),
url('^bump$', views.submit_bump, name='devhub.submit.bump'), url('^bump$', views.submit_bump, name='devhub.submit.bump'),
) )
@ -104,8 +103,7 @@ detail_patterns = patterns(
url('^submit/', include(submit_patterns)), url('^submit/', include(submit_patterns)),
url('^submit/resume$', views.submit_resume, name='devhub.submit.resume'), url('^submit/resume$', views.submit_resume, name='devhub.submit.resume'),
url('^request-review/(?P<status>[%s])$' url('^request-review$',
% ''.join(map(str, views.REQUEST_REVIEW)),
views.request_review, name='devhub.request-review'), views.request_review, name='devhub.request-review'),
url('^rmlocale$', views.remove_locale, name='devhub.addons.remove-locale'), url('^rmlocale$', views.remove_locale, name='devhub.addons.remove-locale'),
) )
@ -178,8 +176,6 @@ urlpatterns = decorate(write, patterns(
url('^feed/%s$' % ADDON_ID, views.feed, name='devhub.feed'), url('^feed/%s$' % ADDON_ID, views.feed, name='devhub.feed'),
url('^upload$', views.upload, name='devhub.upload'), url('^upload$', views.upload, name='devhub.upload'),
url('^upload/sideload$', partial(views.upload, is_listed=False),
name='devhub.upload_sideload'),
url('^upload/unlisted$', url('^upload/unlisted$',
partial(views.upload, is_listed=False, automated=True), partial(views.upload, is_listed=False, automated=True),
name='devhub.upload_unlisted'), name='devhub.upload_unlisted'),
@ -194,10 +190,6 @@ urlpatterns = decorate(write, patterns(
partial(views.upload, is_standalone=True, is_listed=False, partial(views.upload, is_standalone=True, is_listed=False,
automated=True), automated=True),
name='devhub.standalone_upload_unlisted'), name='devhub.standalone_upload_unlisted'),
url('^standalone-upload-sideload$',
partial(views.upload, is_standalone=True, is_listed=False),
name='devhub.standalone_upload_sideload'),
url('^standalone-upload/([^/]+)$', views.standalone_upload_detail, url('^standalone-upload/([^/]+)$', views.standalone_upload_detail,
name='devhub.standalone_upload_detail'), name='devhub.standalone_upload_detail'),

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

@ -314,8 +314,6 @@ class ValidationAnnotator(object):
return return
version = Version(version) version = Version(version)
statuses = (amo.STATUS_PUBLIC, amo.STATUS_LITE)
# Find any previous version of this add-on with the correct status # Find any previous version of this add-on with the correct status
# to match the given file. # to match the given file.
files = File.objects.filter(version__addon=self.addon) files = File.objects.filter(version__addon=self.addon)
@ -325,13 +323,9 @@ class ValidationAnnotator(object):
# TODO: We'll also need to implement this for FileUploads # TODO: We'll also need to implement this for FileUploads
# when we can accurately determine whether a new upload # when we can accurately determine whether a new upload
# is a beta version. # is a beta version.
if self.addon.status in (amo.STATUS_PUBLIC, amo.STATUS_NOMINATED, files = files.filter(status=amo.STATUS_PUBLIC)
amo.STATUS_LITE_AND_NOMINATED):
files = files.filter(status=amo.STATUS_PUBLIC)
else:
files = files.filter(status__in=statuses)
else: else:
files = files.filter(Q(status__in=statuses) | files = files.filter(Q(status=amo.STATUS_PUBLIC) |
Q(status=amo.STATUS_BETA, is_signed=True)) Q(status=amo.STATUS_BETA, is_signed=True))
if self.file: if self.file:

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

@ -20,7 +20,6 @@ from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
import commonware.log import commonware.log
import waffle
from django_statsd.clients import statsd from django_statsd.clients import statsd
from PIL import Image from PIL import Image
@ -380,11 +379,8 @@ def enable(request, addon_id, addon):
@dev_required(owner_for_post=True) @dev_required(owner_for_post=True)
@post_required @post_required
def cancel(request, addon_id, addon): def cancel(request, addon_id, addon):
if addon.status in amo.UNDER_REVIEW_STATUSES: if addon.status == amo.STATUS_NOMINATED:
if addon.status == amo.STATUS_LITE_AND_NOMINATED: addon.update(status=amo.STATUS_NULL)
addon.update(status=amo.STATUS_LITE)
else:
addon.update(status=amo.STATUS_NULL)
amo.log(amo.LOG.CHANGE_STATUS, addon.get_status_display(), addon) amo.log(amo.LOG.CHANGE_STATUS, addon.get_status_display(), addon)
return redirect(addon.get_dev_url('versions')) return redirect(addon.get_dev_url('versions'))
@ -607,7 +603,7 @@ def check_addon_compatibility(request):
def handle_upload(filedata, user, app_id=None, version_id=None, addon=None, def handle_upload(filedata, user, app_id=None, version_id=None, addon=None,
is_standalone=False, is_listed=True, automated=False, is_standalone=False, is_listed=True, automated=False,
submit=False, disallow_preliminary_review=False): submit=False):
if addon: if addon:
# TODO: Handle betas. # TODO: Handle betas.
automated = addon.automated_signing automated = addon.automated_signing
@ -626,9 +622,7 @@ def handle_upload(filedata, user, app_id=None, version_id=None, addon=None,
ver = get_object_or_404(AppVersion, pk=version_id) ver = get_object_or_404(AppVersion, pk=version_id)
tasks.compatibility_check.delay(upload.pk, app.guid, ver.version) tasks.compatibility_check.delay(upload.pk, app.guid, ver.version)
elif submit: elif submit:
tasks.validate_and_submit( tasks.validate_and_submit(addon, upload, listed=is_listed)
addon, upload, listed=is_listed,
disallow_preliminary_review=disallow_preliminary_review)
else: else:
tasks.validate(upload, listed=is_listed) tasks.validate(upload, listed=is_listed)
@ -642,12 +636,10 @@ def upload(request, addon=None, is_standalone=False, is_listed=True,
filedata = request.FILES['upload'] filedata = request.FILES['upload']
app_id = request.POST.get('app_id') app_id = request.POST.get('app_id')
version_id = request.POST.get('version_id') version_id = request.POST.get('version_id')
no_prelim = waffle.flag_is_active(request, 'no-prelim-review')
upload = handle_upload( upload = handle_upload(
filedata=filedata, user=request.user, app_id=app_id, filedata=filedata, user=request.user, app_id=app_id,
version_id=version_id, addon=addon, is_standalone=is_standalone, version_id=version_id, addon=addon, is_standalone=is_standalone,
is_listed=is_listed, automated=automated, is_listed=is_listed, automated=automated)
disallow_preliminary_review=no_prelim)
if addon: if addon:
return redirect('devhub.upload_detail_for_addon', return redirect('devhub.upload_detail_for_addon',
addon.slug, upload.uuid.hex) addon.slug, upload.uuid.hex)
@ -1174,7 +1166,7 @@ def version_edit(request, addon_id, addon, version_id):
return redirect('devhub.versions.edit', addon.slug, version_id) return redirect('devhub.versions.edit', addon.slug, version_id)
data.update(addon=addon, version=version, new_file_form=new_file_form, data.update(addon=addon, version=version, new_file_form=new_file_form,
is_admin=is_admin) is_admin=is_admin, choices=File.STATUS_CHOICES)
return render(request, 'devhub/versions/edit.html', data) return render(request, 'devhub/versions/edit.html', data)
@ -1249,20 +1241,11 @@ def auto_sign_file(file_, is_beta=False):
# Provide the file to review/sign to the helper. # Provide the file to review/sign to the helper.
helper.set_data({'addon_files': [file_], helper.set_data({'addon_files': [file_],
'comments': 'automatic validation'}) 'comments': 'automatic validation'})
if addon.is_sideload: helper.handler.process_public(auto_validation=True)
helper.handler.process_public(auto_validation=True) if validation.passed_auto_validation:
if validation.passed_auto_validation: amo.log(amo.LOG.UNLISTED_SIGNED_VALIDATION_PASSED, file_)
amo.log(amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_PASSED,
file_)
else:
amo.log(amo.LOG.UNLISTED_SIDELOAD_SIGNED_VALIDATION_FAILED,
file_)
else: else:
helper.handler.process_preliminary(auto_validation=True) amo.log(amo.LOG.UNLISTED_SIGNED_VALIDATION_FAILED, file_)
if validation.passed_auto_validation:
amo.log(amo.LOG.UNLISTED_SIGNED_VALIDATION_PASSED, file_)
else:
amo.log(amo.LOG.UNLISTED_SIGNED_VALIDATION_FAILED, file_)
def auto_sign_version(version, **kwargs): def auto_sign_version(version, **kwargs):
@ -1306,12 +1289,8 @@ def version_add(request, addon_id, addon):
log.info('Version created: %s for: %s' % log.info('Version created: %s for: %s' %
(version.pk, form.cleaned_data['upload'])) (version.pk, form.cleaned_data['upload']))
check_validation_override(request, form, addon, version) check_validation_override(request, form, addon, version)
if waffle.flag_is_active(request, 'no-prelim-review'): if addon.status == amo.STATUS_NULL:
if addon.status == amo.STATUS_NULL: addon.update(status=amo.STATUS_NOMINATED)
addon.update(status=amo.STATUS_NOMINATED)
elif (addon.status == amo.STATUS_NULL and
form.cleaned_data['nomination_type']):
addon.update(status=form.cleaned_data['nomination_type'])
url = reverse('devhub.versions.edit', url = reverse('devhub.versions.edit',
args=[addon.slug, str(version.id)]) args=[addon.slug, str(version.id)])
@ -1346,7 +1325,8 @@ def version_add_file(request, addon_id, addon, version_id):
auto_sign_file(new_file, is_beta=is_beta) auto_sign_file(new_file, is_beta=is_beta)
return render(request, 'devhub/includes/version_file.html', return render(request, 'devhub/includes/version_file.html',
{'form': form[0], 'addon': addon}) {'form': form[0], 'addon': addon,
'choices': File.STATUS_CHOICES})
@dev_required @dev_required
@ -1405,7 +1385,7 @@ def submit_step(outer_step):
@functools.wraps(f) @functools.wraps(f)
def wrapper(request, *args, **kw): def wrapper(request, *args, **kw):
step = outer_step step = outer_step
max_step = 7 max_step = 6
# We only bounce on pages with an addon id. # We only bounce on pages with an addon id.
if 'addon' in kw: if 'addon' in kw:
addon = kw['addon'] addon = kw['addon']
@ -1417,7 +1397,7 @@ def submit_step(outer_step):
return redirect(_step_url(max_step), addon.slug) return redirect(_step_url(max_step), addon.slug)
elif step != max_step: elif step != max_step:
# We couldn't find a step, so we must be done. # We couldn't find a step, so we must be done.
return redirect(_step_url(7), addon.slug) return redirect(_step_url(6), addon.slug)
kw['step'] = Step(step, max_step) kw['step'] = Step(step, max_step)
return f(request, *args, **kw) return f(request, *args, **kw)
# Tell @dev_required that this is a function in the submit flow so it # Tell @dev_required that this is a function in the submit flow so it
@ -1464,11 +1444,7 @@ def submit_addon(request, step):
check_validation_override(request, form, addon, check_validation_override(request, form, addon,
addon.current_version) addon.current_version)
if not addon.is_listed: # Not listed? Automatically choose queue. if not addon.is_listed: # Not listed? Automatically choose queue.
no_prelim = waffle.flag_is_active(request, 'no-prelim-review') addon.update(status=amo.STATUS_NOMINATED)
if data.get('is_sideload') or no_prelim: # Full review needed.
addon.update(status=amo.STATUS_NOMINATED)
else: # Otherwise, simply do a prelim review.
addon.update(status=amo.STATUS_UNREVIEWED)
# Sign all the files submitted, one for each platform. # Sign all the files submitted, one for each platform.
auto_sign_version(addon.versions.get()) auto_sign_version(addon.versions.get())
SubmitStep.objects.create(addon=addon, step=3) SubmitStep.objects.create(addon=addon, step=3)
@ -1498,7 +1474,7 @@ def submit_describe(request, addon_id, addon, step):
else: # Finished for unlisted addons. else: # Finished for unlisted addons.
submit_step.delete() submit_step.delete()
signals.submission_done.send(sender=addon) signals.submission_done.send(sender=addon)
return redirect('devhub.submit.7', addon.slug) return redirect('devhub.submit.6', addon.slug)
return render(request, 'devhub/addons/submit/describe.html', return render(request, 'devhub/addons/submit/describe.html',
{'form': form, 'cat_form': cat_form, 'addon': addon, {'form': form, 'cat_form': cat_form, 'addon': addon,
'step': step}) 'step': step})
@ -1545,14 +1521,11 @@ def submit_license(request, addon_id, addon, step):
if license_form in fs: if license_form in fs:
license_form.save(log=False) license_form.save(log=False)
policy_form.save() policy_form.save()
if waffle.flag_is_active(request, 'no-prelim-review'):
addon.update(status=amo.STATUS_NOMINATED) addon.update(status=amo.STATUS_NOMINATED)
SubmitStep.objects.filter(addon=addon).delete() SubmitStep.objects.filter(addon=addon).delete()
signals.submission_done.send(sender=addon) signals.submission_done.send(sender=addon)
return redirect('devhub.submit.7', addon.slug) return redirect('devhub.submit.6', addon.slug)
else:
SubmitStep.objects.filter(addon=addon).update(step=6)
return redirect('devhub.submit.6', addon.slug)
ctx.update(addon=addon, policy_form=policy_form, step=step) ctx.update(addon=addon, policy_form=policy_form, step=step)
return render(request, 'devhub/addons/submit/license.html', ctx) return render(request, 'devhub/addons/submit/license.html', ctx)
@ -1560,26 +1533,6 @@ def submit_license(request, addon_id, addon, step):
@dev_required @dev_required
@submit_step(6) @submit_step(6)
def submit_select_review(request, addon_id, addon, step):
review_type_form = forms.ReviewTypeForm(request.POST or None)
updated_status = None
if request.method == 'POST' and review_type_form.is_valid():
updated_status = review_type_form.cleaned_data['review_type']
if updated_status:
addon.update(status=updated_status)
SubmitStep.objects.filter(addon=addon).delete()
signals.submission_done.send(sender=addon)
return redirect('devhub.submit.7', addon.slug)
return render(request, 'devhub/addons/submit/select-review.html',
{'addon': addon, 'review_type_form': review_type_form,
'step': step})
@dev_required
@submit_step(7)
def submit_done(request, addon_id, addon, step): def submit_done(request, addon_id, addon, step):
# Bounce to the versions page if they don't have any versions. # Bounce to the versions page if they don't have any versions.
if not addon.versions.exists(): if not addon.versions.exists():
@ -1689,32 +1642,15 @@ def remove_locale(request, addon_id, addon, theme):
return http.HttpResponseBadRequest() return http.HttpResponseBadRequest()
# You can only request one of the new review tracks.
REQUEST_REVIEW = (amo.STATUS_PUBLIC, amo.STATUS_LITE)
@dev_required @dev_required
@post_required @post_required
def request_review(request, addon_id, addon, status): def request_review(request, addon_id, addon):
status_req = int(status) if amo.STATUS_PUBLIC not in addon.can_request_review(
no_prelim = waffle.flag_is_active(request, 'no-prelim-review') disallow_preliminary_review=True):
if status_req not in addon.can_request_review(no_prelim):
return http.HttpResponseBadRequest() return http.HttpResponseBadRequest()
elif status_req == amo.STATUS_PUBLIC:
if addon.status == amo.STATUS_LITE:
new_status = amo.STATUS_LITE_AND_NOMINATED
else:
new_status = amo.STATUS_NOMINATED
elif status_req == amo.STATUS_LITE:
if addon.status in (amo.STATUS_PUBLIC, amo.STATUS_LITE_AND_NOMINATED):
new_status = amo.STATUS_LITE
else:
new_status = amo.STATUS_UNREVIEWED
addon.update(status=new_status) addon.update(status=amo.STATUS_NOMINATED)
msg = {amo.STATUS_LITE: _('Preliminary Review Requested.'), messages.success(request, _('Full Review Requested.'))
amo.STATUS_PUBLIC: _('Full Review Requested.')}
messages.success(request, msg[status_req])
amo.log(amo.LOG.CHANGE_STATUS, addon.get_status_display(), addon) amo.log(amo.LOG.CHANGE_STATUS, addon.get_status_display(), addon)
return redirect(addon.get_dev_url('versions')) return redirect(addon.get_dev_url('versions'))

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

@ -173,7 +173,7 @@ class File(OnChangeMixin, ModelBase):
file_.is_experiment = parse_data.get('is_experiment', False) file_.is_experiment = parse_data.get('is_experiment', False)
file_.is_webextension = parse_data.get('is_webextension', False) file_.is_webextension = parse_data.get('is_webextension', False)
if is_beta and addon.status == amo.STATUS_PUBLIC: if is_beta and addon.status == amo.STATUS_PUBLIC and addon.is_listed:
file_.status = amo.STATUS_BETA file_.status = amo.STATUS_BETA
file_.hash = file_.generate_hash(upload.path) file_.hash = file_.generate_hash(upload.path)

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

@ -112,7 +112,7 @@ class TestUploadVersion(BaseUploadVersionCase):
addon = qs.get() addon = qs.get()
assert addon.has_author(self.user) assert addon.has_author(self.user)
assert not addon.is_listed assert not addon.is_listed
assert addon.status == amo.STATUS_LITE assert addon.status == amo.STATUS_NOMINATED
self.auto_sign_version.assert_called_with( self.auto_sign_version.assert_called_with(
addon.latest_version, is_beta=False) addon.latest_version, is_beta=False)
@ -211,7 +211,7 @@ class TestUploadVersion(BaseUploadVersionCase):
addon = qs.get() addon = qs.get()
assert addon.has_author(self.user) assert addon.has_author(self.user)
assert not addon.is_listed assert not addon.is_listed
assert addon.status == amo.STATUS_LITE assert addon.status == amo.STATUS_NOMINATED
self.auto_sign_version.assert_called_with( self.auto_sign_version.assert_called_with(
addon.latest_version, is_beta=False) addon.latest_version, is_beta=False)
@ -230,7 +230,7 @@ class TestUploadVersion(BaseUploadVersionCase):
def test_version_is_beta_unlisted(self): def test_version_is_beta_unlisted(self):
Addon.objects.get(guid=self.guid).update( Addon.objects.get(guid=self.guid).update(
status=amo.STATUS_LITE, is_listed=False) status=amo.STATUS_PUBLIC, is_listed=False)
version_string = '4.0-beta1' version_string = '4.0-beta1'
qs = Version.objects.filter( qs = Version.objects.filter(
addon__guid=self.guid, version=version_string) addon__guid=self.guid, version=version_string)
@ -246,7 +246,7 @@ class TestUploadVersion(BaseUploadVersionCase):
assert version.addon.guid == self.guid assert version.addon.guid == self.guid
assert version.version == version_string assert version.version == version_string
assert version.statuses[0][1] == amo.STATUS_UNREVIEWED assert version.statuses[0][1] == amo.STATUS_UNREVIEWED
assert version.addon.status == amo.STATUS_LITE assert version.addon.status == amo.STATUS_PUBLIC
assert not version.is_beta assert not version.is_beta
self.auto_sign_version.assert_called_with(version, is_beta=False) self.auto_sign_version.assert_called_with(version, is_beta=False)
@ -355,7 +355,7 @@ class TestUploadVersionWebextension(BaseUploadVersionCase):
assert version.files.all()[0].is_webextension is True assert version.files.all()[0].is_webextension is True
assert addon.has_author(self.user) assert addon.has_author(self.user)
assert not addon.is_listed assert not addon.is_listed
assert addon.status == amo.STATUS_LITE assert addon.status == amo.STATUS_NOMINATED
self.auto_sign_version.assert_called_with( self.auto_sign_version.assert_called_with(
addon.latest_version, is_beta=False) addon.latest_version, is_beta=False)

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

@ -5,7 +5,6 @@ from django import forms
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import waffle
from rest_framework import status from rest_framework import status
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
@ -156,10 +155,8 @@ class VersionView(APIView):
else: else:
created = False created = False
no_prelim = waffle.flag_is_active(request, 'no-prelim-review')
file_upload = handle_upload( file_upload = handle_upload(
filedata=filedata, user=request.user, addon=addon, submit=True, filedata=filedata, user=request.user, addon=addon, submit=True)
disallow_preliminary_review=no_prelim)
return file_upload, created return file_upload, created

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

@ -303,7 +303,6 @@
var $newForm = $('.new-addon-file'); var $newForm = $('.new-addon-file');
var $isUnlistedCheckbox = $('#id_is_unlisted'); var $isUnlistedCheckbox = $('#id_is_unlisted');
var $isSideloadCheckbox = $('#id_is_sideload');
function isUnlisted() { function isUnlisted() {
// True if there's a '#id_is_unlisted' checkbox that is checked, or a // True if there's a '#id_is_unlisted' checkbox that is checked, or a
@ -312,19 +311,11 @@
(typeof($newForm.data('addon-is-listed')) != 'undefined' && !$newForm.data('addon-is-listed'))); (typeof($newForm.data('addon-is-listed')) != 'undefined' && !$newForm.data('addon-is-listed')));
} }
function isSideload() {
// True if there's a '#id_is_sideload' checkbox that is checked, or a
// 'addon-is-sideload' data on the new file form that is true.
return (($isSideloadCheckbox.length && $isSideloadCheckbox.is(':checked')) ||
(typeof($newForm.data('addon-is-sideload')) != 'undefined' && $newForm.data('addon-is-sideload')));
}
// is_unlisted checkbox: should the add-on be listed on AMO? If not, // is_unlisted checkbox: should the add-on be listed on AMO? If not,
// change the addon upload button's data-upload-url. // change the addon upload button's data-upload-url.
// If this add-on is unlisted, then tell the upload view so // If this add-on is unlisted, then tell the upload view so
// it'll run the validator with the "listed=False" // it'll run the validator with the "listed=False"
// parameter. // parameter.
var $isSideloadLabel = $('label[for=id_is_sideload]');
var $submitAddonProgress = $('.submit-addon-progress'); var $submitAddonProgress = $('.submit-addon-progress');
function updateListedStatus() { function updateListedStatus() {
if (!isUnlisted()) { // It's a listed add-on. if (!isUnlisted()) { // It's a listed add-on.
@ -334,16 +325,9 @@
// doesn't upload to the correct url. Using // doesn't upload to the correct url. Using
// .attr('data-upload-url', val) instead fixes that. // .attr('data-upload-url', val) instead fixes that.
$upload_field.attr('data-upload-url', $upload_field.data('upload-url-listed')); $upload_field.attr('data-upload-url', $upload_field.data('upload-url-listed'));
$isSideloadLabel.hide();
$isSideloadCheckbox.prop('checked', false);
$submitAddonProgress.removeClass('unlisted'); $submitAddonProgress.removeClass('unlisted');
} else { // It's an unlisted add-on. } else { // It's an unlisted add-on.
if (isSideload()) { // It's a sideload add-on. $upload_field.attr('data-upload-url', $upload_field.data('upload-url-unlisted'));
$upload_field.attr('data-upload-url', $upload_field.data('upload-url-sideload'));
} else {
$upload_field.attr('data-upload-url', $upload_field.data('upload-url-unlisted'));
}
$isSideloadLabel.show();
$submitAddonProgress.addClass('unlisted'); $submitAddonProgress.addClass('unlisted');
} }
/* Don't allow submitting, need to reupload/revalidate the file. */ /* Don't allow submitting, need to reupload/revalidate the file. */
@ -353,7 +337,6 @@
$('.upload-status').remove(); $('.upload-status').remove();
} }
$isUnlistedCheckbox.bind('change', updateListedStatus); $isUnlistedCheckbox.bind('change', updateListedStatus);
$isSideloadCheckbox.bind('change', updateListedStatus);
updateListedStatus(); updateListedStatus();
$('#id_is_manual_review').bind('change', function() { $('#id_is_manual_review').bind('change', function() {
@ -444,7 +427,6 @@
$("<strong>").text(message).appendTo(upload_results); $("<strong>").text(message).appendTo(upload_results);
// Specific messages for unlisted addons. // Specific messages for unlisted addons.
var isSideload = $('#id_is_sideload').is(':checked') || $newForm.data('addon-is-sideload');
if (isUnlisted()) { if (isUnlisted()) {
$("<p>").text(gettext("Your submission will be automatically signed.")).appendTo(upload_results); $("<p>").text(gettext("Your submission will be automatically signed.")).appendTo(upload_results);
} }