Expose is_restart_required property on files in the search/detail API (#5858)
* Expose is_restart_required property on files in the search/detail API * Fix mapping tests * Replace no_restart field (and HTML/CSS for consistency) by is_restart_required * Move migration now that 953 is taken * Remove old model field entirely.
This commit is contained in:
Родитель
b994908e52
Коммит
a9aa802333
|
@ -299,6 +299,7 @@ This endpoint allows you to fetch a single version belonging to a specific add-o
|
|||
:>json string files[].hash: The hash for a file.
|
||||
:>json string files[].platform: The :ref:`platform <addon-detail-platform>` for a file.
|
||||
:>json int files[].id: The size for a file, in bytes.
|
||||
:>json boolean files[].is_restart_required: Whether the file requires a browser restart to work once installed or not.
|
||||
:>json boolean files[].is_webextension: Whether the file is a WebExtension or not.
|
||||
:>json int files[].status: The :ref:`status <addon-detail-status>` for a file.
|
||||
:>json string files[].url: The (absolute) URL to download a file. An optional ``src`` query parameter can be added to indicate the source page (See :ref:`download sources <download-sources>`).
|
||||
|
|
|
@ -537,7 +537,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2014-12-08T06:39:45",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
|
@ -559,7 +559,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2014-12-08T06:40:07",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
|
@ -581,7 +581,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2014-12-08T06:40:16",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
|
@ -603,7 +603,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2014-12-08T06:40:23",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
|
@ -625,7 +625,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2014-12-08T06:40:24",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
|
@ -647,7 +647,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2014-12-08T06:40:25",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
|
|
|
@ -301,7 +301,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2011-12-05 14:46:43",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"binary": false,
|
||||
"binary_components": false,
|
||||
"size": 0
|
||||
|
@ -323,7 +323,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2011-12-05 14:46:43",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"binary": false,
|
||||
"binary_components": false,
|
||||
"size": 0
|
||||
|
@ -345,7 +345,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2011-12-05 14:46:43",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"binary": false,
|
||||
"binary_components": false,
|
||||
"size": 0
|
||||
|
@ -367,7 +367,7 @@
|
|||
"jetpack_version": null,
|
||||
"requires_chrome": false,
|
||||
"datestatuschanged": "2011-12-05 14:46:43",
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"binary": false,
|
||||
"binary_components": false,
|
||||
"size": 0
|
||||
|
|
|
@ -53,6 +53,8 @@ class AddonIndexer(BaseSearchIndexer):
|
|||
'filename': {
|
||||
'type': 'string', 'index': 'no'},
|
||||
'is_webextension': {'type': 'boolean'},
|
||||
'is_restart_required': {
|
||||
'type': 'boolean', 'index': 'no'},
|
||||
'platform': {
|
||||
'type': 'byte', 'index': 'no'},
|
||||
'size': {'type': 'long', 'index': 'no'},
|
||||
|
@ -167,6 +169,7 @@ class AddonIndexer(BaseSearchIndexer):
|
|||
'filename': file_.filename,
|
||||
'hash': file_.hash,
|
||||
'is_webextension': file_.is_webextension,
|
||||
'is_restart_required': file_.is_restart_required,
|
||||
'platform': file_.platform,
|
||||
'size': file_.size,
|
||||
'status': file_.status,
|
||||
|
|
|
@ -1206,10 +1206,11 @@ class Addon(OnChangeMixin, ModelBase):
|
|||
return get_featured_ids(app, lang)
|
||||
|
||||
@property
|
||||
def requires_restart(self):
|
||||
def is_restart_required(self):
|
||||
"""Whether the add-on current version requires a browser restart to
|
||||
work."""
|
||||
return self.current_version and self.current_version.requires_restart
|
||||
return (
|
||||
self.current_version and self.current_version.is_restart_required)
|
||||
|
||||
def is_featured(self, app, lang=None):
|
||||
"""Is add-on globally featured for this app and language?"""
|
||||
|
|
|
@ -34,11 +34,13 @@ class FileSerializer(serializers.ModelSerializer):
|
|||
permissions = serializers.ListField(
|
||||
source='webext_permissions_list',
|
||||
child=serializers.CharField())
|
||||
is_restart_required = serializers.BooleanField()
|
||||
|
||||
class Meta:
|
||||
model = File
|
||||
fields = ('id', 'created', 'hash', 'is_webextension', 'platform',
|
||||
'size', 'status', 'url', 'permissions')
|
||||
fields = ('id', 'created', 'hash', 'is_restart_required',
|
||||
'is_webextension', 'platform', 'size', 'status', 'url',
|
||||
'permissions')
|
||||
|
||||
def get_url(self, obj):
|
||||
# File.get_url_path() is a little different, it's already absolute, but
|
||||
|
@ -319,6 +321,7 @@ class ESBaseAddonSerializer(BaseESSerializer):
|
|||
id=data['id'], created=self.handle_date(data['created']),
|
||||
hash=data['hash'], filename=data['filename'],
|
||||
is_webextension=data.get('is_webextension'),
|
||||
is_restart_required=data.get('is_restart_required', False),
|
||||
platform=data['platform'], size=data['size'],
|
||||
status=data['status'], version=obj)
|
||||
file_.webext_permissions_list = data.get('webext_permissions_list', [])
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
|
||||
{% macro addon_flags(addon, version) %}
|
||||
{% if version %}
|
||||
{% if version.requires_restart %}
|
||||
<span class="requires-restart">{{ _('Requires Restart') }}</span>
|
||||
{% if version.is_restart_required %}
|
||||
<span class="is-restart-required">{{ _('Requires Restart') }}</span>
|
||||
{% elif version.is_webextension %}
|
||||
<a href="https://support.mozilla.org/kb/firefox-add-technology-modernizing" class="is-webextension" title="{{ _('This add-on is built with new technology that is compatible with Firefox 57 and beyond.') }}">{{ _('Compatible with Firefox 57+') }}</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -116,8 +116,9 @@ class TestAddonIndexer(TestCase):
|
|||
# Make sure files mapping is set inside current_version.
|
||||
files_mapping = version_mapping['files']['properties']
|
||||
expected_file_keys = (
|
||||
'id', 'created', 'filename', 'hash', 'is_webextension', 'platform',
|
||||
'size', 'status', 'webext_permissions_list')
|
||||
'id', 'created', 'filename', 'hash', 'is_webextension',
|
||||
'is_restart_required', 'platform', 'size', 'status',
|
||||
'webext_permissions_list')
|
||||
assert set(files_mapping.keys()) == set(expected_file_keys)
|
||||
|
||||
def _extract(self):
|
||||
|
@ -208,6 +209,9 @@ class TestAddonIndexer(TestCase):
|
|||
assert extracted_file['created'] == file_.created
|
||||
assert extracted_file['filename'] == file_.filename
|
||||
assert extracted_file['hash'] == file_.hash
|
||||
assert extracted_file['is_webextension'] == file_.is_webextension
|
||||
assert extracted_file['is_restart_required'] == (
|
||||
file_.is_restart_required)
|
||||
assert extracted_file['platform'] == file_.platform
|
||||
assert extracted_file['size'] == file_.size
|
||||
assert extracted_file['status'] == file_.status
|
||||
|
@ -233,6 +237,9 @@ class TestAddonIndexer(TestCase):
|
|||
assert extracted_file['created'] == file_.created
|
||||
assert extracted_file['filename'] == file_.filename
|
||||
assert extracted_file['hash'] == file_.hash
|
||||
assert extracted_file['is_webextension'] == file_.is_webextension
|
||||
assert extracted_file['is_restart_required'] == (
|
||||
file_.is_restart_required)
|
||||
assert extracted_file['platform'] == file_.platform
|
||||
assert extracted_file['size'] == file_.size
|
||||
assert extracted_file['status'] == file_.status
|
||||
|
@ -259,6 +266,9 @@ class TestAddonIndexer(TestCase):
|
|||
assert extracted_file['created'] == file_.created
|
||||
assert extracted_file['filename'] == file_.filename
|
||||
assert extracted_file['hash'] == file_.hash
|
||||
assert extracted_file['is_webextension'] == file_.is_webextension
|
||||
assert extracted_file['is_restart_required'] == (
|
||||
file_.is_restart_required)
|
||||
assert extracted_file['platform'] == file_.platform
|
||||
assert extracted_file['size'] == file_.size
|
||||
assert extracted_file['status'] == file_.status
|
||||
|
|
|
@ -736,19 +736,18 @@ class TestAddonModels(TestCase):
|
|||
addon.disabled_by_user = True
|
||||
assert not addon.is_public()
|
||||
|
||||
def test_requires_restart(self):
|
||||
def test_is_restart_required(self):
|
||||
addon = Addon.objects.get(pk=3615)
|
||||
file_ = addon.current_version.all_files[0]
|
||||
assert not file_.no_restart
|
||||
assert file_.requires_restart
|
||||
assert addon.requires_restart
|
||||
assert not file_.is_restart_required
|
||||
assert not addon.is_restart_required
|
||||
|
||||
file_.update(no_restart=True)
|
||||
assert not Addon.objects.get(pk=3615).requires_restart
|
||||
file_.update(is_restart_required=True)
|
||||
assert Addon.objects.get(pk=3615).is_restart_required
|
||||
|
||||
addon.versions.all().delete()
|
||||
addon._current_version = None
|
||||
assert not addon.requires_restart
|
||||
assert not addon.is_restart_required
|
||||
|
||||
def test_is_featured(self):
|
||||
"""Test if an add-on is globally featured"""
|
||||
|
|
|
@ -56,6 +56,7 @@ class AddonSerializerOutputTestMixin(object):
|
|||
assert result_file['created'] == (
|
||||
file_.created.replace(microsecond=0).isoformat() + 'Z')
|
||||
assert result_file['hash'] == file_.hash
|
||||
assert result_file['is_restart_required'] == file_.is_restart_required
|
||||
assert result_file['is_webextension'] == file_.is_webextension
|
||||
assert result_file['platform'] == (
|
||||
amo.PLATFORM_CHOICES_API[file_.platform])
|
||||
|
@ -83,6 +84,7 @@ class AddonSerializerOutputTestMixin(object):
|
|||
description=u'My Addôn description',
|
||||
file_kw={
|
||||
'hash': 'fakehash',
|
||||
'is_restart_required': False,
|
||||
'is_webextension': True,
|
||||
'platform': amo.PLATFORM_WIN.id,
|
||||
'size': 42,
|
||||
|
@ -427,8 +429,7 @@ class AddonSerializerOutputTestMixin(object):
|
|||
'http://testserver/static/img/addon-icons/default-64.png')
|
||||
|
||||
def test_webextension(self):
|
||||
self.addon = addon_factory(
|
||||
file_kw={'is_webextension': True})
|
||||
self.addon = addon_factory(file_kw={'is_webextension': True})
|
||||
# Give one of the versions some webext permissions to test that.
|
||||
WebextPermission.objects.create(
|
||||
file=self.addon.current_version.all_files[0],
|
||||
|
@ -443,6 +444,13 @@ class AddonSerializerOutputTestMixin(object):
|
|||
assert result['current_version']['files'][0]['permissions'] == ([
|
||||
'bookmarks', 'random permission'])
|
||||
|
||||
def test_is_restart_required(self):
|
||||
self.addon = addon_factory(file_kw={'is_restart_required': True})
|
||||
result = self.serialize()
|
||||
|
||||
self._test_version(
|
||||
self.addon.current_version, result['current_version'])
|
||||
|
||||
|
||||
class TestAddonSerializerOutput(AddonSerializerOutputTestMixin, TestCase):
|
||||
serializer_class = AddonSerializer
|
||||
|
|
|
@ -926,19 +926,18 @@ class TestDetailPage(TestCase):
|
|||
self.addon.save()
|
||||
assert pq(self.client.get(self.url).content)(selector)
|
||||
|
||||
def test_requires_restart(self):
|
||||
span_restart = '<span class="requires-restart">Requires Restart</span>'
|
||||
f = self.addon.current_version.all_files[0]
|
||||
def test_is_restart_required(self):
|
||||
span_is_restart_required = (
|
||||
'<span class="is-restart-required">Requires Restart</span>')
|
||||
file_ = self.addon.current_version.all_files[0]
|
||||
|
||||
assert f.requires_restart is True
|
||||
r = self.client.get(self.url)
|
||||
assert span_restart in r.content
|
||||
assert file_.is_restart_required is False
|
||||
response = self.client.get(self.url)
|
||||
assert span_is_restart_required not in response.content
|
||||
|
||||
f.no_restart = True
|
||||
f.save()
|
||||
assert f.requires_restart is False
|
||||
r = self.client.get(self.url)
|
||||
assert span_restart not in r.content
|
||||
file_.update(is_restart_required=True)
|
||||
response = self.client.get(self.url)
|
||||
assert span_is_restart_required in response.content
|
||||
|
||||
def test_is_webextension(self):
|
||||
file_ = self.addon.current_version.all_files[0]
|
||||
|
@ -948,7 +947,7 @@ class TestDetailPage(TestCase):
|
|||
doc = pq(response.content)
|
||||
assert not doc('a.is-webextension')
|
||||
|
||||
file_.update(is_webextension=True, no_restart=True)
|
||||
file_.update(is_webextension=True, is_restart_required=False)
|
||||
assert file_.is_webextension is True
|
||||
response = self.client.get(self.url)
|
||||
doc = pq(response.content)
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
"model": "files.file",
|
||||
"fields": {
|
||||
"status": 4,
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"hash": "sha256:bc96230b5a777433089f88b93e09279b90c8eb1821c0e1c930e9e19111bc9803",
|
||||
"created": "2011-05-06 09:30:50",
|
||||
"modified": "2011-05-06 09:30:50",
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
"model": "files.file",
|
||||
"fields": {
|
||||
"status": 1,
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"hash": "sha256:a300e3943309aee1e1ee47f569f9be36276791b3e66596be4c9cc4ee238b01b6",
|
||||
"created": "2010-12-17 13:04:57",
|
||||
"modified": "2010-12-17 13:04:57",
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
"model": "files.file",
|
||||
"fields": {
|
||||
"status": 1,
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"hash": "sha256:a300e3943309aee1e1ee47f569f9be36276791b3e66596be4c9cc4ee238b01b6",
|
||||
"created": "2010-12-17 13:04:57",
|
||||
"modified": "2010-12-17 13:04:57",
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
"model": "files.file",
|
||||
"fields": {
|
||||
"status": 1,
|
||||
"no_restart": false,
|
||||
"is_restart_required": true,
|
||||
"hash": "sha256:1a496e35dd56fb377bb3dea306e285f0a3ff3e684fb758aaa04018e86da2ffaa",
|
||||
"created": "2010-08-27 21:15:32",
|
||||
"modified": "2010-08-27 21:15:32",
|
||||
|
|
|
@ -32,7 +32,7 @@ user_log = olympia.core.logger.getLogger('z.users')
|
|||
VIEW_QUEUE_FLAGS = (
|
||||
('admin_review', 'admin-review', _('Admin Review')),
|
||||
('is_jetpack', 'jetpack', _('Jetpack Add-on')),
|
||||
('requires_restart', 'requires_restart', _('Requires Restart')),
|
||||
('is_restart_required', 'is_restart_required', _('Requires Restart')),
|
||||
('has_info_request', 'info', _('More Information Requested')),
|
||||
('has_editor_comment', 'editor', _('Contains Reviewer Comment')),
|
||||
('sources_provided', 'sources-provided', _('Sources provided')),
|
||||
|
@ -129,7 +129,7 @@ class ViewQueue(RawSQLModel):
|
|||
addon_status = models.IntegerField()
|
||||
addon_type_id = models.IntegerField()
|
||||
admin_review = models.BooleanField()
|
||||
is_restartless = models.BooleanField()
|
||||
is_restart_required = models.BooleanField()
|
||||
is_jetpack = models.BooleanField()
|
||||
source = models.CharField(max_length=100)
|
||||
is_webextension = models.BooleanField()
|
||||
|
@ -153,7 +153,7 @@ class ViewQueue(RawSQLModel):
|
|||
('has_editor_comment', 'versions.has_editor_comment'),
|
||||
('has_info_request', 'versions.has_info_request'),
|
||||
('is_jetpack', 'MAX(files.jetpack_version IS NOT NULL)'),
|
||||
('is_restartless', 'MAX(files.no_restart)'),
|
||||
('is_restart_required', 'MAX(files.is_restart_required)'),
|
||||
('source', 'versions.source'),
|
||||
('is_webextension', 'MAX(files.is_webextension)'),
|
||||
('waiting_time_days',
|
||||
|
@ -181,10 +181,6 @@ class ViewQueue(RawSQLModel):
|
|||
],
|
||||
'group_by': 'id'}
|
||||
|
||||
@property
|
||||
def requires_restart(self):
|
||||
return not self.is_restartless
|
||||
|
||||
@property
|
||||
def sources_provided(self):
|
||||
return bool(self.source)
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
<div id="addon-summary-wrapper">
|
||||
<div id="addon-summary" class="primary">
|
||||
<p{{ addon.summary|locale_html }}>{{ addon.summary|nl2br }}</p>
|
||||
{% if version and version.requires_restart %}
|
||||
<div id="requires-restart" class="js-hidden">
|
||||
<span id="requires-restart-msg">{{ _('Requires Restart') }}</span>
|
||||
{% if version and version.is_restart_required %}
|
||||
<div>
|
||||
<span>{{ _('Requires Restart') }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -104,7 +104,8 @@ class TestPendingQueue(TestQueue):
|
|||
'created': self.days_ago(1)})
|
||||
version_factory(
|
||||
addon=addon, version=version, channel=self.channel,
|
||||
file_kw={'status': amo.STATUS_AWAITING_REVIEW, 'no_restart': True})
|
||||
file_kw={'status': amo.STATUS_AWAITING_REVIEW,
|
||||
'is_restart_required': False})
|
||||
return addon
|
||||
|
||||
def new_search_ext(self, name, version, **kw):
|
||||
|
@ -146,12 +147,12 @@ class TestPendingQueue(TestQueue):
|
|||
q = self.Queue.objects.get()
|
||||
assert q.flags == [('jetpack', 'Jetpack Add-on')]
|
||||
|
||||
def test_flags_requires_restart(self):
|
||||
def test_flags_is_restart_required(self):
|
||||
self.new_addon().find_latest_version(self.channel).all_files[0].update(
|
||||
no_restart=False)
|
||||
is_restart_required=True)
|
||||
|
||||
q = self.Queue.objects.get()
|
||||
assert q.flags == [('requires_restart', 'Requires Restart')]
|
||||
assert q.flags == [('is_restart_required', 'Requires Restart')]
|
||||
|
||||
def test_flags_sources_provided(self):
|
||||
self.new_addon().find_latest_version(self.channel).update(
|
||||
|
|
|
@ -909,12 +909,12 @@ class TestQueueBasics(QueueTest):
|
|||
assert rows.find('td').eq(1).text() == 'Jetpack 0.1'
|
||||
assert rows.find('.ed-sprite-jetpack').length == 1
|
||||
|
||||
def test_flags_requires_restart(self):
|
||||
def test_flags_is_restart_required(self):
|
||||
addon = addon_factory(
|
||||
status=amo.STATUS_NOMINATED, name='Some Add-on',
|
||||
version_kw={'version': '0.1'},
|
||||
file_kw={'status': amo.STATUS_AWAITING_REVIEW,
|
||||
'no_restart': False})
|
||||
'is_restart_required': True})
|
||||
|
||||
r = self.client.get(reverse('editors.queue_nominated'))
|
||||
|
||||
|
@ -923,14 +923,14 @@ class TestQueueBasics(QueueTest):
|
|||
assert rows.attr('data-addon') == str(addon.id)
|
||||
assert rows.find('td').eq(1).text() == 'Some Add-on 0.1'
|
||||
assert rows.find('.ed-sprite-jetpack').length == 0
|
||||
assert rows.find('.ed-sprite-requires_restart').length == 1
|
||||
assert rows.find('.ed-sprite-is_restart_required').length == 1
|
||||
|
||||
def test_flags_no_restart(self):
|
||||
def test_flags_is_restart_required_false(self):
|
||||
addon = addon_factory(
|
||||
status=amo.STATUS_NOMINATED, name='Restartless',
|
||||
version_kw={'version': '0.1'},
|
||||
file_kw={'status': amo.STATUS_AWAITING_REVIEW,
|
||||
'no_restart': True})
|
||||
'is_restart_required': False})
|
||||
|
||||
r = self.client.get(reverse('editors.queue_nominated'))
|
||||
|
||||
|
@ -939,7 +939,7 @@ class TestQueueBasics(QueueTest):
|
|||
assert rows.attr('data-addon') == str(addon.id)
|
||||
assert rows.find('td').eq(1).text() == 'Restartless 0.1'
|
||||
assert rows.find('.ed-sprite-jetpack').length == 0
|
||||
assert rows.find('.ed-sprite-requires_restart').length == 0
|
||||
assert rows.find('.ed-sprite-is_restart_required').length == 0
|
||||
|
||||
def test_theme_redirect(self):
|
||||
users = []
|
||||
|
@ -1857,13 +1857,13 @@ class TestReview(ReviewBase):
|
|||
assert self.client.head(self.url).status_code == 200
|
||||
|
||||
def test_not_flags(self):
|
||||
self.addon.current_version.files.update(no_restart=True)
|
||||
self.addon.current_version.files.update(is_restart_required=False)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
assert len(response.context['flags']) == 0
|
||||
|
||||
def test_flag_admin_review(self):
|
||||
self.addon.current_version.files.update(no_restart=True)
|
||||
self.addon.current_version.files.update(is_restart_required=False)
|
||||
self.addon.update(admin_review=True)
|
||||
response = self.client.get(self.url)
|
||||
assert len(response.context['flags']) == 1
|
||||
|
|
|
@ -63,7 +63,7 @@ class File(OnChangeMixin, ModelBase):
|
|||
status = models.PositiveSmallIntegerField(
|
||||
choices=STATUS_CHOICES.items(), default=amo.STATUS_AWAITING_REVIEW)
|
||||
datestatuschanged = models.DateTimeField(null=True, auto_now_add=True)
|
||||
no_restart = models.BooleanField(default=False)
|
||||
is_restart_required = models.BooleanField(default=False)
|
||||
strict_compatibility = models.BooleanField(default=False)
|
||||
# The XPI contains JS that calls require("chrome").
|
||||
requires_chrome = models.BooleanField(default=False)
|
||||
|
@ -117,13 +117,6 @@ class File(OnChangeMixin, ModelBase):
|
|||
return (self.version.channel == amo.RELEASE_CHANNEL_UNLISTED or
|
||||
self.status == amo.STATUS_BETA)
|
||||
|
||||
@property
|
||||
def requires_restart(self):
|
||||
"""Whether the add-on file requires a browser restart to work."""
|
||||
# For historical purposes the field we store is "no_restart", which
|
||||
# is exactly the opposite.
|
||||
return not self.no_restart
|
||||
|
||||
def get_file_cdn_url(self, attachment=False):
|
||||
"""Return the URL for the file corresponding to this instance
|
||||
on the CDN."""
|
||||
|
@ -164,9 +157,10 @@ class File(OnChangeMixin, ModelBase):
|
|||
data = cls.get_jetpack_metadata(upload.path)
|
||||
if 'sdkVersion' in data and data['sdkVersion']:
|
||||
file_.jetpack_version = data['sdkVersion'][:10]
|
||||
file_.no_restart = parsed_data.get('no_restart', False)
|
||||
file_.strict_compatibility = parsed_data.get('strict_compatibility',
|
||||
False)
|
||||
file_.is_restart_required = parsed_data.get(
|
||||
'is_restart_required', False)
|
||||
file_.strict_compatibility = parsed_data.get(
|
||||
'strict_compatibility', False)
|
||||
file_.is_multi_package = parsed_data.get('is_multi_package', False)
|
||||
file_.is_experiment = parsed_data.get('is_experiment', False)
|
||||
file_.is_webextension = parsed_data.get('is_webextension', False)
|
||||
|
@ -565,7 +559,7 @@ def track_file_status_change(file_):
|
|||
statsd.incr('file_status_change.all.status_{}'.format(file_.status))
|
||||
|
||||
if (file_.jetpack_version and
|
||||
file_.no_restart and
|
||||
not file_.is_restart_required and
|
||||
not file_.requires_chrome):
|
||||
statsd.incr('file_status_change.jetpack_sdk_only.status_{}'
|
||||
.format(file_.status))
|
||||
|
|
|
@ -376,7 +376,7 @@ class TestTrackFileStatusChange(TestCase):
|
|||
f = self.create_file(
|
||||
status=amo.STATUS_PUBLIC,
|
||||
jetpack_version='1.0',
|
||||
no_restart=True,
|
||||
is_restart_required=False,
|
||||
requires_chrome=False,
|
||||
)
|
||||
with patch('olympia.files.models.statsd.incr') as mock_incr:
|
||||
|
@ -490,20 +490,20 @@ class TestParseXpi(TestCase):
|
|||
# See bug 1220097: telemetry experiments (type 128) map to extensions.
|
||||
assert parsed['type'] == amo.ADDON_EXTENSION
|
||||
assert parsed['is_experiment']
|
||||
assert parsed['no_restart']
|
||||
assert not parsed['is_restart_required']
|
||||
|
||||
def test_match_type_extension_for_webextension_experiments(self):
|
||||
parsed = self.parse(filename='webextension_experiment.xpi')
|
||||
# See #3315: webextension experiments (type 256) map to extensions.
|
||||
assert parsed['type'] == amo.ADDON_EXTENSION
|
||||
assert parsed['is_experiment']
|
||||
assert parsed['no_restart']
|
||||
assert not parsed['is_restart_required']
|
||||
|
||||
def test_match_type_extension_for_webextensions(self):
|
||||
parsed = self.parse(filename='webextension.xpi')
|
||||
assert parsed['type'] == amo.ADDON_EXTENSION
|
||||
assert parsed['is_webextension']
|
||||
assert parsed['no_restart']
|
||||
assert not parsed['is_restart_required']
|
||||
|
||||
def test_xml_for_extension(self):
|
||||
addon = Addon.objects.create(guid='guid@xpi', type=1)
|
||||
|
@ -525,20 +525,20 @@ class TestParseXpi(TestCase):
|
|||
result = self.parse(filename='dictionary-test.xpi')
|
||||
assert result['type'] == amo.ADDON_DICT
|
||||
# We detected it as a dictionary but it's not using the explicit
|
||||
# dictionary type, so it's not restartless.
|
||||
assert not result['no_restart']
|
||||
# dictionary type, so it will require a restart.
|
||||
assert result['is_restart_required']
|
||||
|
||||
def test_parse_dictionary_explicit_type(self):
|
||||
result = self.parse(filename='dictionary-explicit-type-test.xpi')
|
||||
assert result['type'] == amo.ADDON_DICT
|
||||
assert result['no_restart']
|
||||
assert not result['is_restart_required']
|
||||
|
||||
def test_parse_dictionary_extension(self):
|
||||
result = self.parse(filename='dictionary-extension-test.xpi')
|
||||
assert result['type'] == amo.ADDON_EXTENSION
|
||||
# It's not a real dictionary, it's an extension, so it's not
|
||||
# restartless.
|
||||
assert not result['no_restart']
|
||||
# It's not a real dictionary, it's an extension, so it will require a
|
||||
# restart.
|
||||
assert result['is_restart_required']
|
||||
|
||||
def test_parse_jar(self):
|
||||
result = self.parse(filename='theme.jar')
|
||||
|
@ -563,7 +563,7 @@ class TestParseXpi(TestCase):
|
|||
def test_parse_langpack(self):
|
||||
result = self.parse(filename='langpack.xpi')
|
||||
assert result['type'] == amo.ADDON_LPAPP
|
||||
assert result['no_restart']
|
||||
assert not result['is_restart_required']
|
||||
|
||||
def test_good_version_number(self):
|
||||
check_xpi_info({'guid': 'guid', 'version': '1.2a-b+32*__yeah'})
|
||||
|
@ -997,19 +997,19 @@ class TestFileFromUpload(UploadTest):
|
|||
assert f.hash.startswith('sha256:')
|
||||
assert len(f.hash) == 64 + 7 # 64 for hash, 7 for 'sha256:'
|
||||
|
||||
def test_no_restart_true(self):
|
||||
def test_does_not_requires_a_restart(self):
|
||||
upload = self.upload('jetpack')
|
||||
data = parse_addon(upload.path)
|
||||
file_ = File.from_upload(upload, self.version, self.platform,
|
||||
parsed_data=data)
|
||||
assert file_.no_restart
|
||||
assert not file_.is_restart_required
|
||||
|
||||
def test_no_restart_false(self):
|
||||
def test_does_require_a_restart(self):
|
||||
upload = self.upload('extension')
|
||||
data = parse_addon(upload.path)
|
||||
file_ = File.from_upload(upload, self.version, self.platform,
|
||||
parsed_data=data)
|
||||
assert not file_.no_restart
|
||||
assert file_.is_restart_required
|
||||
|
||||
def test_utf8(self):
|
||||
upload = self.upload(u'jétpack')
|
||||
|
@ -1073,7 +1073,7 @@ class TestFileFromUpload(UploadTest):
|
|||
file_ = File.from_upload(upload, self.version, self.platform,
|
||||
parsed_data=data)
|
||||
assert file_.filename.endswith('.xpi')
|
||||
assert file_.no_restart
|
||||
assert not file_.is_restart_required
|
||||
|
||||
def test_search_extension(self):
|
||||
upload = self.upload('search.xml')
|
||||
|
@ -1081,7 +1081,7 @@ class TestFileFromUpload(UploadTest):
|
|||
file_ = File.from_upload(upload, self.version, self.platform,
|
||||
parsed_data=data)
|
||||
assert file_.filename.endswith('.xml')
|
||||
assert file_.no_restart
|
||||
assert not file_.is_restart_required
|
||||
|
||||
def test_multi_package(self):
|
||||
upload = self.upload('multi-package')
|
||||
|
@ -1221,7 +1221,7 @@ class TestParseSearch(TestCase, amo.tests.AMOPaths):
|
|||
assert self.parse() == {
|
||||
'guid': None,
|
||||
'name': u'search tool',
|
||||
'no_restart': True,
|
||||
'is_restart_required': False,
|
||||
'version': datetime.now().strftime('%Y%m%d'),
|
||||
'summary': u'Search Engine for Firefox',
|
||||
'type': amo.ADDON_SEARCH}
|
||||
|
|
|
@ -183,9 +183,9 @@ class TestManifestJSONExtractor(TestCase):
|
|||
"""manifest.json addons are always ADDON_EXTENSION."""
|
||||
assert self.parse({})['type'] == amo.ADDON_EXTENSION
|
||||
|
||||
def test_no_restart(self):
|
||||
"""manifest.json addons are always no_restart."""
|
||||
assert self.parse({})['no_restart'] is True
|
||||
def test_is_restart_required(self):
|
||||
"""manifest.json addons never requires restart."""
|
||||
assert self.parse({})['is_restart_required'] is False
|
||||
|
||||
def test_name(self):
|
||||
"""Use name for the name."""
|
||||
|
|
|
@ -183,9 +183,9 @@ class RDFExtractor(object):
|
|||
'version': self.find('version'),
|
||||
'homepage': self.find('homepageURL'),
|
||||
'summary': self.find('description'),
|
||||
'no_restart': (
|
||||
self.find('bootstrap') == 'true' or
|
||||
self.find('type') in self.ALWAYS_RESTARTLESS_TYPES),
|
||||
'is_restart_required': (
|
||||
self.find('bootstrap') != 'true' and
|
||||
self.find('type') not in self.ALWAYS_RESTARTLESS_TYPES),
|
||||
'strict_compatibility': self.find('strictCompatibility') == 'true',
|
||||
'apps': self.apps(),
|
||||
'is_multi_package': self.package_type == '32',
|
||||
|
@ -386,7 +386,7 @@ class ManifestJSONExtractor(object):
|
|||
'version': self.get('version', ''),
|
||||
'homepage': self.get('homepage_url'),
|
||||
'summary': self.get('description'),
|
||||
'no_restart': True,
|
||||
'is_restart_required': False,
|
||||
'apps': list(self.apps()),
|
||||
'is_webextension': True,
|
||||
'e10s_compatibility': amo.E10S_COMPATIBLE_WEBEXTENSION,
|
||||
|
@ -427,7 +427,7 @@ def parse_search(fileorpath, addon=None):
|
|||
return {'guid': None,
|
||||
'type': amo.ADDON_SEARCH,
|
||||
'name': data['name'],
|
||||
'no_restart': True,
|
||||
'is_restart_required': False,
|
||||
'summary': data['description'],
|
||||
'version': datetime.now().strftime('%Y%m%d')}
|
||||
|
||||
|
|
|
@ -14,11 +14,6 @@
|
|||
</li>
|
||||
<li><a href="{{ url('addons.detail', addon.slug, src='discovery-learnmore') }}"
|
||||
id="learn-more" class="button">{{ _('Learn More') }}</a></li>
|
||||
{% if addon.requires_restart %}
|
||||
<li id="requires-restart">
|
||||
<span id="requires-restart-msg">{{ _('Requires Restart') }}</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if addon.privacy_policy %}
|
||||
<li class="privacy"><a href="{{ url('addons.privacy', addon.slug, src='discovery-learnmore') }}">
|
||||
{{ _('View Privacy Policy') }}</a></li>
|
||||
|
|
|
@ -356,16 +356,6 @@ class TestDetails(TestCase):
|
|||
def get_addon(self):
|
||||
return Addon.objects.get(id=3615)
|
||||
|
||||
def test_requires_restart(self):
|
||||
f = self.addon.current_version.all_files[0]
|
||||
assert f.requires_restart
|
||||
r = self.client.get(self.detail_url)
|
||||
assert pq(r.content)('#requires-restart').length == 1
|
||||
f.update(no_restart=True)
|
||||
assert not f.requires_restart
|
||||
r = self.client.get(self.detail_url)
|
||||
assert pq(r.content)('#requires-restart').length == 0
|
||||
|
||||
def test_install_button_eula(self):
|
||||
doc = pq(self.client.get(self.detail_url).content)
|
||||
assert doc('#install .install-button').text() == 'Download Now'
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
-- is_restart_required replaces the old no_restart field. It's the exact opposite.
|
||||
ALTER TABLE `files`
|
||||
ADD COLUMN `is_restart_required` bool NOT NULL,
|
||||
MODIFY `no_restart` bool; -- Allow nulls to prepare for column removal next push.
|
||||
UPDATE `files` SET `is_restart_required` = NOT `no_restart`;
|
|
@ -448,8 +448,8 @@ class Version(OnChangeMixin, ModelBase):
|
|||
return False
|
||||
|
||||
@property
|
||||
def requires_restart(self):
|
||||
return any(file_.requires_restart for file_ in self.all_files)
|
||||
def is_restart_required(self):
|
||||
return any(file_.is_restart_required for file_ in self.all_files)
|
||||
|
||||
@property
|
||||
def is_webextension(self):
|
||||
|
|
|
@ -93,16 +93,15 @@ class TestVersion(TestCase):
|
|||
assert v.minor2 is None
|
||||
assert v.minor3 is None
|
||||
|
||||
def test_requires_restart(self):
|
||||
def test_is_restart_required(self):
|
||||
version = Version.objects.get(pk=81551)
|
||||
file_ = version.all_files[0]
|
||||
assert not file_.no_restart
|
||||
assert file_.requires_restart
|
||||
assert version.requires_restart
|
||||
assert not file_.is_restart_required
|
||||
assert not version.is_restart_required
|
||||
|
||||
file_.update(no_restart=True)
|
||||
file_.update(is_restart_required=True)
|
||||
version = Version.objects.get(pk=81551)
|
||||
assert not version.requires_restart
|
||||
assert version.is_restart_required
|
||||
|
||||
def test_is_webextension(self):
|
||||
version = Version.objects.get(pk=81551)
|
||||
|
|
|
@ -490,7 +490,7 @@ h1.addon,
|
|||
}
|
||||
}
|
||||
|
||||
span.requires-restart,
|
||||
span.is-restart-required,
|
||||
div a.is-webextension,
|
||||
span.featured {
|
||||
background-color: #e8933a;
|
||||
|
@ -508,7 +508,7 @@ div a.is-webextension {
|
|||
background-color: #093;
|
||||
}
|
||||
|
||||
.html-rtl span.requires-restart,
|
||||
.html-rtl span.is-restart-required,
|
||||
.html-rtl div a.iswebextension,
|
||||
.html-rtl span.featured {
|
||||
margin: 11px 4px 0 0;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
.ed-sprite-android { background-position: 0 -48px; }
|
||||
.ed-sprite-mobile { background-position: 0 -64px; }
|
||||
.ed-sprite-jetpack { background-position: 0 -80px; }
|
||||
.ed-sprite-requires_restart { background-position: 0 -96px; }
|
||||
.ed-sprite-is_restart_required { background-position: 0 -96px; }
|
||||
.ed-sprite-notes { background-position: 0 -112px; }
|
||||
.ed-sprite-admin-review { background-position: 0 -128px; }
|
||||
.ed-sprite-editor { background-position: 0 -144px; }
|
||||
|
|
|
@ -25,11 +25,4 @@ $(document).ready(function() {
|
|||
|
||||
var etiquette_box = $("#addons-display-review-etiquette").hide();
|
||||
$("#short-review").focus(function() { etiquette_box.show("fast"); } );
|
||||
|
||||
/* Restart required box. (Only shown in Fx4+). */
|
||||
var requires_restart = $('#addon-summary #requires-restart');
|
||||
if (requires_restart.length && z.browser.firefox
|
||||
&& VersionCompare.compareVersions(z.browserVersion, '4.0a1') > 0) {
|
||||
requires_restart.show();
|
||||
}
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче