Exemple #1
0
 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)
Exemple #2
0
 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')
Exemple #3
0
 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")
Exemple #4
0
 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')
Exemple #5
0
 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')
Exemple #6
0
 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')
Exemple #7
0
 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)
Exemple #8
0
 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â')
Exemple #9
0
 def _get_version(self, status):
     v = Version()
     v.all_files = [mock.Mock()]
     v.all_files[0].status = status
     return v
Exemple #10
0
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)
Exemple #11
0
 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')
Exemple #12
0
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)
Exemple #13
0
    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
Exemple #15
0
 def _get_version(self, status):
     v = Version()
     v.all_files = [mock.Mock()]
     v.all_files[0].status = status
     return v
Exemple #16
0
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)
Exemple #17
0
 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')
Exemple #18
0
    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
 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