def test_large_version_int(self): # This version will fail to be written to the version_int # table because the resulting int is bigger than mysql bigint. version = Version(addon=Addon.objects.get(pk=337141)) version.version = '9223372036854775807' version.save() eq_(version.version_int, None)
def test_generate_hash(self, storage_mock): f = File() f.version = Version() # Mock remote storage to use a local file instead of a remote one. storage_mock.open = open filename = self.packaged_app_path('mozball.zip') assert f.generate_hash(filename).startswith('sha256:ad85d6316166d4')
def test_developer_name_from_upload(self, parse_addon): parse_addon.return_value = {"version": "42.0", "developer_name": u"Mýself"} addon = Webapp.objects.get(pk=337141) # Note: we need a valid FileUpload instance, but in the end we are not # using its contents since we are mocking parse_addon(). path = os.path.join(settings.ROOT, "mkt", "developers", "tests", "addons", "mozball.webapp") upload = self.get_upload(abspath=path) version = Version.from_upload(upload, addon) eq_(version.version, "42.0") eq_(version.developer_name, u"Mýself")
def test_developer_name_from_upload(self, parse_webapp): parse_webapp.return_value = { 'version': '42.0', 'developer_name': u'Mýself' } webapp = Webapp.objects.get(pk=337141) # Note: we need a valid FileUpload instance, but in the end we are not # using its contents since we are mocking parse_webapp(). path = os.path.join(settings.ROOT, 'mkt', 'developers', 'tests', 'webapps', 'mozball.webapp') upload = self.get_upload(abspath=path) version = Version.from_upload(upload, webapp) eq_(version.version, '42.0') eq_(version.developer_name, u'Mýself')
def test_developer_name_from_upload(self, parse_addon): parse_addon.return_value = { 'version': '42.0', 'developer_name': u'Mýself' } addon = Webapp.objects.get(pk=337141) # Note: we need a valid FileUpload instance, but in the end we are not # using its contents since we are mocking parse_addon(). path = os.path.join(settings.ROOT, 'mkt', 'developers', 'tests', 'addons', 'mozball.webapp') upload = self.get_upload(abspath=path) version = Version.from_upload(upload, addon) eq_(version.version, '42.0') eq_(version.developer_name, u'Mýself')
def test_developer_name_from_upload(self, parse_addon): parse_addon.return_value = { 'version': '42.0', 'developer_name': u'Mýself' } addon = Addon.objects.get(pk=337141) # Note: we need a valid FileUpload instance, but in the end we are not # using its contents since we are mocking parse_addon(). path = os.path.join(settings.ROOT, 'mkt', 'developers', 'tests', 'addons', 'mozball.webapp') upload = self.get_upload(abspath=path) platform = Platform.objects.get(pk=amo.PLATFORM_ALL.id) version = Version.from_upload(upload, addon, [platform]) eq_(version.version, '42.0') eq_(version.developer_name, u'Mýself')
def test_long_developer_name_from_upload(self, parse_addon): truncated_developer_name = u'ý' * 255 long_developer_name = truncated_developer_name + u'àààà' parse_addon.return_value = { 'version': '42.1', 'developer_name': long_developer_name } addon = Webapp.objects.get(pk=337141) # Note: we need a valid FileUpload instance, but in the end we are not # using its contents since we are mocking parse_addon(). path = os.path.join(settings.ROOT, 'mkt', 'developers', 'tests', 'addons', 'mozball.webapp') upload = self.get_upload(abspath=path) version = Version.from_upload(upload, addon) eq_(version.version, '42.1') eq_(version.developer_name, truncated_developer_name)
def test_developer_name(self): version = Version.objects.latest('id') version._developer_name = u'M€lâ' eq_(version.developer_name, u'M€lâ') eq_(Version(_developer_name=u'M€lâ').developer_name, u'M€lâ')
def _get_version(self, status): v = Version() v.all_files = [mock.Mock()] v.all_files[0].status = status return v
def status(request, addon_id, addon): appeal_form = forms.AppAppealForm(request.POST, product=addon) upload_form = NewWebappVersionForm(request.POST or None, is_packaged=True, addon=addon, request=request) publish_form = forms.PublishForm(request.POST or None, addon=addon) if request.method == 'POST': if 'resubmit-app' in request.POST and appeal_form.is_valid(): if not addon.is_rated(): # Cannot resubmit without content ratings. return http.HttpResponseForbidden( 'This app must obtain content ratings before being ' 'resubmitted.') appeal_form.save() create_comm_note(addon, addon.latest_version, request.user, appeal_form.data['notes'], note_type=comm.RESUBMISSION) if addon.vip_app: handle_vip(addon, addon.latest_version, request.user) messages.success(request, _('App successfully resubmitted.')) return redirect(addon.get_dev_url('versions')) elif 'upload-version' in request.POST and upload_form.is_valid(): upload = upload_form.cleaned_data['upload'] ver = Version.from_upload(upload, addon, [amo.PLATFORM_ALL]) # Update addon status now that the new version was saved. addon.update_status() res = run_validator(ver.all_files[0].file_path) validation_result = json.loads(res) # Escalate the version if it uses prerelease permissions. escalate_prerelease_permissions(addon, validation_result, ver) # Set all detected features as True and save them. keys = ['has_%s' % feature.lower() for feature in validation_result['feature_profile']] data = defaultdict.fromkeys(keys, True) # Set "Smartphone-Sized Displays" if it's a mobile-only app. qhd_devices = (set((amo.DEVICE_GAIA,)), set((amo.DEVICE_MOBILE,)), set((amo.DEVICE_GAIA, amo.DEVICE_MOBILE,))) mobile_only = (addon.latest_version and addon.latest_version.features.has_qhd) if set(addon.device_types) in qhd_devices or mobile_only: data['has_qhd'] = True # Update feature profile for this version. ver.features.update(**data) messages.success(request, _('New version successfully added.')) log.info('[Webapp:%s] New version created id=%s from upload: %s' % (addon, ver.pk, upload)) if addon.vip_app: handle_vip(addon, ver, request.user) return redirect(addon.get_dev_url('versions.edit', args=[ver.pk])) elif 'publish-app' in request.POST and publish_form.is_valid(): publish_form.save() return redirect(addon.get_dev_url('versions')) ctx = {'addon': addon, 'appeal_form': appeal_form, 'upload_form': upload_form, 'publish_form': publish_form} # Used in the delete version modal. if addon.is_packaged: versions = addon.versions.values('id', 'version') version_strings = dict((v['id'], v) for v in versions) version_strings['num'] = len(versions) ctx['version_strings'] = json.dumps(version_strings) if addon.status == amo.STATUS_REJECTED: try: entry = (AppLog.objects .filter(addon=addon, activity_log__action=amo.LOG.REJECT_VERSION.id) .order_by('-created'))[0] except IndexError: entry = None # This contains the rejection reason and timestamp. ctx['rejection'] = entry and entry.activity_log if waffle.switch_is_active('preload-apps'): test_plan = PreloadTestPlan.objects.filter( addon=addon, status=amo.STATUS_PUBLIC) if test_plan.exists(): test_plan = test_plan[0] if (test_plan.last_submission < settings.PREINSTALL_TEST_PLAN_LATEST): ctx['outdated_test_plan'] = True ctx['next_step_suffix'] = 'submit' else: ctx['next_step_suffix'] = 'home' ctx['test_plan'] = test_plan return render(request, 'developers/apps/status.html', ctx)
def test_generate_filename_ja(self): f = File() f.version = Version(version='0.1.7') f.version.addon = Webapp(name=u' フォクすけ といっしょ') eq_(f.generate_filename(), 'none-0.1.7.webapp')
def status(request, addon_id, addon): appeal_form = forms.AppAppealForm(request.POST, product=addon) upload_form = NewWebappVersionForm(request.POST or None, is_packaged=True, addon=addon, request=request) publish_form = forms.PublishForm(request.POST if "publish-app" in request.POST else None, addon=addon) if request.method == "POST": if "resubmit-app" in request.POST and appeal_form.is_valid(): if not addon.is_rated(): # Cannot resubmit without content ratings. return http.HttpResponseForbidden("This app must obtain content ratings before being " "resubmitted.") appeal_form.save() create_comm_note( addon, addon.latest_version, request.user, appeal_form.data["notes"], note_type=comm.RESUBMISSION ) if addon.vip_app: handle_vip(addon, addon.latest_version, request.user) messages.success(request, _("App successfully resubmitted.")) return redirect(addon.get_dev_url("versions")) elif "upload-version" in request.POST and upload_form.is_valid(): upload = upload_form.cleaned_data["upload"] ver = Version.from_upload(upload, addon) # Update addon status now that the new version was saved. addon.update_status() res = run_validator(ver.all_files[0].file_path) validation_result = json.loads(res) # Escalate the version if it uses prerelease permissions. escalate_prerelease_permissions(addon, validation_result, ver) # Set all detected features as True and save them. keys = ["has_%s" % feature.lower() for feature in validation_result["feature_profile"]] data = defaultdict.fromkeys(keys, True) # Set "Smartphone-Sized Displays" if it's a mobile-only app. qhd_devices = ( set((amo.DEVICE_GAIA,)), set((amo.DEVICE_MOBILE,)), set((amo.DEVICE_GAIA, amo.DEVICE_MOBILE)), ) mobile_only = addon.latest_version and addon.latest_version.features.has_qhd if set(addon.device_types) in qhd_devices or mobile_only: data["has_qhd"] = True # Update feature profile for this version. ver.features.update(**data) messages.success(request, _("New version successfully added.")) log.info("[Webapp:%s] New version created id=%s from upload: %s" % (addon, ver.pk, upload)) if addon.vip_app: handle_vip(addon, ver, request.user) return redirect(addon.get_dev_url("versions.edit", args=[ver.pk])) elif "publish-app" in request.POST and publish_form.is_valid(): publish_form.save() return redirect(addon.get_dev_url("versions")) ctx = { "addon": addon, "appeal_form": appeal_form, "is_tarako": addon.tags.filter(tag_text=QUEUE_TARAKO).exists(), "tarako_review": addon.additionalreview_set.latest_for_queue(QUEUE_TARAKO), "publish_form": publish_form, "QUEUE_TARAKO": QUEUE_TARAKO, "upload_form": upload_form, } # Used in the delete version modal. if addon.is_packaged: versions = addon.versions.values("id", "version") version_strings = dict((v["id"], v) for v in versions) version_strings["num"] = len(versions) ctx["version_strings"] = json.dumps(version_strings) if addon.status == amo.STATUS_REJECTED: try: entry = ( AppLog.objects.filter(addon=addon, activity_log__action=amo.LOG.REJECT_VERSION.id).order_by("-created") )[0] except IndexError: entry = None # This contains the rejection reason and timestamp. ctx["rejection"] = entry and entry.activity_log if waffle.switch_is_active("preload-apps"): test_plan = PreloadTestPlan.objects.filter(addon=addon, status=amo.STATUS_PUBLIC) if test_plan.exists(): test_plan = test_plan[0] if test_plan.last_submission < settings.PREINSTALL_TEST_PLAN_LATEST: ctx["outdated_test_plan"] = True ctx["next_step_suffix"] = "submit" else: ctx["next_step_suffix"] = "home" ctx["test_plan"] = test_plan return render(request, "developers/apps/status.html", ctx)
def fake_object(self, data): """Create a fake instance of Webapp and related models from ES data.""" is_packaged = data['app_type'] != amo.ADDON_WEBAPP_HOSTED is_privileged = data['app_type'] == amo.ADDON_WEBAPP_PRIVILEGED obj = Webapp(id=data['id'], app_slug=data['app_slug'], is_packaged=is_packaged, icon_type='image/png') # Set relations and attributes we need on those relations. # The properties set on latest_version and current_version differ # because we are only setting what the serializer is going to need. # In particular, latest_version.is_privileged needs to be set because # it's used by obj.app_type_id. obj.listed_authors = [] obj._current_version = Version() obj._current_version.addon = obj obj._current_version._developer_name = data['author'] obj._current_version.supported_locales = data['supported_locales'] obj._current_version.version = data['current_version'] obj._latest_version = Version() obj._latest_version.is_privileged = is_privileged obj._geodata = Geodata() obj.all_previews = [ Preview(id=p['id'], modified=self.to_datetime(p['modified']), filetype=p['filetype'], sizes=p.get('sizes', {})) for p in data['previews'] ] obj.categories = data['category'] obj._device_types = [DEVICE_TYPES[d] for d in data['device']] obj._is_disabled = data['is_disabled'] # Set base attributes on the "fake" app using the data from ES. self._attach_fields( obj, data, ('created', 'modified', 'default_locale', 'icon_hash', 'is_escalated', 'is_offline', 'manifest_url', 'premium_type', 'regions', 'reviewed', 'status', 'weekly_downloads')) # Attach translations for all translated attributes. self._attach_translations( obj, data, ('name', 'description', 'homepage', 'release_notes', 'support_email', 'support_url')) if data.get('group_translations'): self._attach_translations(obj, data, ('group', )) # Feed group. else: obj.group_translations = None self._attach_translations(obj._geodata, data, ('banner_message', )) # Set attributes that have a different name in ES. obj.public_stats = data['has_public_stats'] # Override obj.get_region() with a static list of regions generated # from the region_exclusions stored in ES. obj.get_regions = obj.get_regions( obj.get_region_ids(restofworld=True, excluded=data['region_exclusions'])) # Some methods below will need the raw data from ES, put it on obj. obj.es_data = data return obj
def create_version(self, addon, upload): """Create new Version instance from a FileUpload instance""" self.info('Creating new Version...') version = Version.from_upload(upload, addon) self.info('Created new Version %s.' % version) return version
def status(request, addon_id, addon): appeal_form = forms.AppAppealForm(request.POST, product=addon) upload_form = NewWebappVersionForm(request.POST or None, is_packaged=True, addon=addon, request=request) publish_form = forms.PublishForm( request.POST if 'publish-app' in request.POST else None, addon=addon) if request.method == 'POST': if 'resubmit-app' in request.POST and appeal_form.is_valid(): if not addon.is_rated(): # Cannot resubmit without content ratings. return http.HttpResponseForbidden( 'This app must obtain content ratings before being ' 'resubmitted.') appeal_form.save() create_comm_note(addon, addon.latest_version, request.user, appeal_form.data['notes'], note_type=comm.RESUBMISSION) if addon.vip_app: handle_vip(addon, addon.latest_version, request.user) messages.success(request, _('App successfully resubmitted.')) return redirect(addon.get_dev_url('versions')) elif 'upload-version' in request.POST and upload_form.is_valid(): upload = upload_form.cleaned_data['upload'] ver = Version.from_upload(upload, addon) # Update addon status now that the new version was saved. addon.update_status() res = run_validator(ver.all_files[0].file_path) validation_result = json.loads(res) # Escalate the version if it uses prerelease permissions. escalate_prerelease_permissions(addon, validation_result, ver) # Set all detected features as True and save them. keys = [ 'has_%s' % feature.lower() for feature in validation_result['feature_profile'] ] data = defaultdict.fromkeys(keys, True) # Set "Smartphone-Sized Displays" if it's a mobile-only app. qhd_devices = (set((amo.DEVICE_GAIA, )), set( (amo.DEVICE_MOBILE, )), set(( amo.DEVICE_GAIA, amo.DEVICE_MOBILE, ))) mobile_only = (addon.latest_version and addon.latest_version.features.has_qhd) if set(addon.device_types) in qhd_devices or mobile_only: data['has_qhd'] = True # Update feature profile for this version. ver.features.update(**data) messages.success(request, _('New version successfully added.')) log.info('[Webapp:%s] New version created id=%s from upload: %s' % (addon, ver.pk, upload)) if addon.vip_app: handle_vip(addon, ver, request.user) return redirect(addon.get_dev_url('versions.edit', args=[ver.pk])) elif 'publish-app' in request.POST and publish_form.is_valid(): publish_form.save() return redirect(addon.get_dev_url('versions')) ctx = { 'addon': addon, 'appeal_form': appeal_form, 'is_tarako': addon.tags.filter(tag_text=QUEUE_TARAKO).exists(), 'tarako_review': addon.additionalreview_set.latest_for_queue(QUEUE_TARAKO), 'publish_form': publish_form, 'QUEUE_TARAKO': QUEUE_TARAKO, 'upload_form': upload_form, } # Used in the delete version modal. if addon.is_packaged: versions = addon.versions.values('id', 'version') version_strings = dict((v['id'], v) for v in versions) version_strings['num'] = len(versions) ctx['version_strings'] = json.dumps(version_strings) if addon.status == amo.STATUS_REJECTED: try: entry = (AppLog.objects.filter( addon=addon, activity_log__action=amo.LOG.REJECT_VERSION.id).order_by( '-created'))[0] except IndexError: entry = None # This contains the rejection reason and timestamp. ctx['rejection'] = entry and entry.activity_log if waffle.switch_is_active('preload-apps'): test_plan = PreloadTestPlan.objects.filter(addon=addon, status=amo.STATUS_PUBLIC) if test_plan.exists(): test_plan = test_plan[0] if (test_plan.last_submission < settings.PREINSTALL_TEST_PLAN_LATEST): ctx['outdated_test_plan'] = True ctx['next_step_suffix'] = 'submit' else: ctx['next_step_suffix'] = 'home' ctx['test_plan'] = test_plan return render(request, 'developers/apps/status.html', ctx)
def test_generate_webapp_fn_partial_non_ascii(self): f = File() f.version = Version(version='0.1.7') f.version.addon = Webapp(app_slug=u'myapp フォクすけ といっしょ') eq_(f.generate_filename(), 'myapp-0.1.7.webapp')
def fake_object(self, data): """Create a fake instance of Webapp and related models from ES data.""" is_packaged = data['app_type'] != mkt.ADDON_WEBAPP_HOSTED is_privileged = data['app_type'] == mkt.ADDON_WEBAPP_PRIVILEGED obj = Webapp(id=data['id'], app_slug=data['app_slug'], is_packaged=is_packaged, icon_type='image/png') # Set relations and attributes we need on those relations. # The properties set on latest_version and current_version differ # because we are only setting what the serializer is going to need. # In particular, latest_version.is_privileged needs to be set because # it's used by obj.app_type_id. obj.listed_authors = [] obj._current_version = Version() obj._current_version.addon = obj obj._current_version._developer_name = data['author'] obj._current_version.supported_locales = data['supported_locales'] obj._current_version.version = data['current_version'] obj._latest_version = Version() obj._latest_version.is_privileged = is_privileged obj._geodata = Geodata() obj.all_previews = [ Preview(id=p['id'], modified=self.to_datetime(p['modified']), filetype=p['filetype'], sizes=p.get('sizes', {})) for p in data['previews'] ] obj.categories = data['category'] obj.tags_list = data['tags'] obj._device_types = [DEVICE_TYPES[d] for d in data['device']] obj._is_disabled = data['is_disabled'] # Set base attributes on the "fake" app using the data from ES. self._attach_fields( obj, data, ('created', 'default_locale', 'guid', 'icon_hash', 'is_escalated', 'is_offline', 'last_updated', 'hosted_url', 'manifest_url', 'modified', 'premium_type', 'promo_img_hash', 'regions', 'reviewed', 'status')) # Attach translations for all translated attributes. self._attach_translations(obj, data, ('name', 'description', 'homepage', 'support_email', 'support_url')) if data.get('group_translations'): self._attach_translations(obj, data, ('group', )) # Feed group. else: obj.group_translations = None # Release notes target and source name differ (ES stores it as # release_notes but the db field we are emulating is called # releasenotes without the "_"). ESTranslationSerializerField.attach_translations( obj._current_version, data, 'release_notes', target_name='releasenotes') # Set attributes that have a different name in ES. obj.public_stats = data['has_public_stats'] # Override obj.get_excluded_region_ids() to just return the list of # regions stored in ES instead of making SQL queries. obj.get_excluded_region_ids = lambda: data['region_exclusions'] # Set up payments stuff to avoid extra queries later (we'll still make # some, because price info is not in ES). if obj.is_premium(): Webapp.attach_premiums([obj]) # Some methods below will need the raw data from ES, put it on obj. obj.es_data = data return obj