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:
Mathieu Pillard 2017-07-11 13:44:37 +02:00 коммит произвёл GitHub
Родитель b994908e52
Коммит a9aa802333
31 изменённых файлов: 133 добавлений и 136 удалений

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

@ -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();
}
});