예제 #1
0
    def test_default_locale(self):
        # Make sure default_locale follows the active translation.
        addon = Addon.from_upload(self.get_upload('search.xml'),
                                  [self.platform])
        eq_(addon.default_locale, 'en-US')

        translation.activate('es-ES')
        addon = Addon.from_upload(self.get_upload('search.xml'),
                                  [self.platform])
        eq_(addon.default_locale, 'es-ES')
        translation.deactivate()
예제 #2
0
파일: views.py 프로젝트: darkwing/zamboni
def package(request):
    form = forms.NewWebappForm(request.POST or None, is_packaged=True)
    if request.method == 'POST' and form.is_valid():
        addon = Addon.from_upload(
            form.cleaned_data['upload'],
            [Platform.objects.get(id=amo.PLATFORM_ALL.id)], is_packaged=True)

        if addon.has_icon_in_manifest():
            # Fetch the icon, do polling.
            addon.update(icon_type='image/png')
            tasks.fetch_icon.delay(addon)
        else:
            # In this case there is no need to do any polling.
            addon.update(icon_type='')

        AddonUser(addon=addon, user=request.amo_user).save()
        AppSubmissionChecklist.objects.create(addon=addon, terms=True,
                                              manifest=True)

        return redirect('submit.app.details', addon.app_slug)

    return jingo.render(request, 'submit/upload.html', {
        'form': form,
        'step': 'manifest',
    })
예제 #3
0
    def obj_create(self, bundle, request, **kwargs):
        form = UploadForm(bundle.data)

        if not request.amo_user.read_dev_agreement:
            log.info(u'Attempt to use API without dev agreement: %s'
                     % request.amo_user.pk)
            raise http_error(http.HttpUnauthorized,
                             'Terms of service not accepted.')

        if not form.is_valid():
            raise self.form_errors(form)

        if not (OwnerAuthorization()
                .is_authorized(request, object=form.obj)):
            raise http_error(http.HttpForbidden,
                             'You do not own that app.')

        plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)]

        # Create app, user and fetch the icon.
        bundle.obj = Addon.from_upload(form.obj, plats,
                                       is_packaged=form.is_packaged)
        AddonUser(addon=bundle.obj, user=request.amo_user).save()

        self._icons_and_images(bundle.obj)
        record_action('app-submitted', request, {'app-id': bundle.obj.pk})

        log.info('App created: %s' % bundle.obj.pk)
        return bundle
예제 #4
0
def package(request):
    form = forms.NewWebappForm(request.POST or None, is_packaged=True)
    if request.method == 'POST' and form.is_valid():
        addon = Addon.from_upload(
            form.cleaned_data['upload'],
            [Platform.objects.get(id=amo.PLATFORM_ALL.id)],
            is_packaged=True)

        if addon.has_icon_in_manifest():
            # Fetch the icon, do polling.
            addon.update(icon_type='image/png')
            tasks.fetch_icon.delay(addon)
        else:
            # In this case there is no need to do any polling.
            addon.update(icon_type='')

        AddonUser(addon=addon, user=request.amo_user).save()
        AppSubmissionChecklist.objects.create(addon=addon,
                                              terms=True,
                                              manifest=True)

        return redirect('submit.app.details', addon.app_slug)

    return jingo.render(request, 'submit/upload.html', {
        'form': form,
        'step': 'manifest',
    })
예제 #5
0
 def test_xpi_version(self):
     addon = Addon.from_upload(self.get_upload('extension.xpi'),
                               [self.platform])
     v = addon.versions.get()
     eq_(v.version, '0.1')
     eq_(v.files.get().platform_id, self.platform.id)
     eq_(v.files.get().status, amo.STATUS_UNREVIEWED)
예제 #6
0
def manifest(request):
    # TODO: Have decorator handle the redirection.
    user = UserProfile.objects.get(pk=request.user.id)
    if not user.read_dev_agreement:
        # And we start back at one...
        return redirect('submit.app')

    form = forms.NewWebappForm(request.POST or None)
    if request.method == 'POST' and form.is_valid():
        data = form.cleaned_data

        plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)]
        addon = Addon.from_upload(data['upload'], plats)
        if addon.has_icon_in_manifest():
            # Fetch the icon, do polling.
            addon.update(icon_type='image/png')
            tasks.fetch_icon.delay(addon)
        else:
            # In this case there is no need to do any polling.
            addon.update(icon_type='')

        AddonUser(addon=addon, user=request.amo_user).save()
        # Checking it once. Checking it twice.
        AppSubmissionChecklist.objects.create(addon=addon, terms=True,
                                              manifest=True)

        return redirect('submit.app.details', addon.app_slug)

    return jingo.render(request, 'submit/manifest.html', {
        'step': 'manifest',
        'form': form,
    })
예제 #7
0
 def test_search_version(self):
     addon = Addon.from_upload(self.get_upload('search.xml'),
                               [self.platform])
     v = addon.versions.get()
     eq_(v.version, datetime.now().strftime('%Y%m%d'))
     eq_(v.files.get().platform_id, amo.PLATFORM_ALL.id)
     eq_(v.files.get().status, amo.STATUS_UNREVIEWED)
예제 #8
0
    def obj_create(self, bundle, request, **kwargs):
        form = UploadForm(bundle.data)

        if not request.amo_user.read_dev_agreement:
            log.info(u'Attempt to use API without dev agreement: %s'
                     % request.amo_user.pk)
            response = http.HttpUnauthorized()
            response.content = json.dumps({'reason':
                                           'Terms of service not accepted.'})
            raise ImmediateHttpResponse(response=response)

        if not form.is_valid():
            raise self.form_errors(form)

        if not (OwnerAuthorization()
                .is_authorized(request, object=form.obj)):
            raise ImmediateHttpResponse(response=http.HttpForbidden())

        plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)]

        # Create app, user and fetch the icon.
        bundle.obj = Addon.from_upload(form.obj, plats,
                                       is_packaged=form.is_packaged)
        AddonUser(addon=bundle.obj, user=request.amo_user).save()

        self._icons_and_images(bundle.obj)
        record_action('app-submitted', request, {'app-id': bundle.obj.pk})

        log.info('App created: %s' % bundle.obj.pk)
        return bundle
예제 #9
0
    def create(self, request):
        if not waffle.flag_is_active(request, 'accept-webapps'):
            return rc.BAD_REQUEST

        form = NewManifestForm(request.POST)
        if form.is_valid():
            # This feels like an awful lot of work.
            # But first upload the file and do the validation.
            upload = FileUpload.objects.create()
            tasks.fetch_manifest(form.cleaned_data['manifest'], upload.pk)

            # We must reget the object here since the above has
            # saved changes to the object.
            upload = FileUpload.uncached.get(pk=upload.pk)
            # Check it validated correctly.
            if settings.VALIDATE_ADDONS:
                validation = json.loads(upload.validation)
                if validation['errors']:
                    response = rc.BAD_REQUEST
                    response.write(validation)
                    return response

            # Fetch the addon, the icon and set the user.
            addon = Addon.from_upload(upload,
                        [Platform.objects.get(id=amo.PLATFORM_ALL.id)])
            tasks.fetch_icon(addon)
            AddonUser(addon=addon, user=request.amo_user).save()
            addon.update(status=amo.STATUS_PENDING if
                         settings.WEBAPPS_RESTRICTED else amo.STATUS_PUBLIC)

        else:
            return _form_error(form)
        return addon
예제 #10
0
파일: views.py 프로젝트: rtilder/zamboni
def manifest(request):
    form = forms.NewWebappForm(request.POST or None)

    if request.method == "POST" and form.is_valid():
        addon = Addon.from_upload(
            form.cleaned_data["upload"], [Platform.objects.get(id=amo.PLATFORM_ALL.id)], is_packaged=form.is_packaged()
        )

        # Set the device type.
        for device in form.get_devices():
            addon.addondevicetype_set.get_or_create(device_type=device.id)

        # Set the premium type, only bother if it's not free.
        premium = form.get_paid()
        if premium:
            addon.update(premium_type=premium)

        if addon.has_icon_in_manifest():
            # Fetch the icon, do polling.
            addon.update(icon_type="image/png")
            tasks.fetch_icon.delay(addon)
        else:
            # In this case there is no need to do any polling.
            addon.update(icon_type="")

        AddonUser(addon=addon, user=request.amo_user).save()
        # Checking it once. Checking it twice.
        AppSubmissionChecklist.objects.create(addon=addon, terms=True, manifest=True)

        return redirect("submit.app.details", addon.app_slug)

    return jingo.render(
        request, "submit/manifest.html", {"step": "manifest", "form": form, "DEVICE_LOOKUP": DEVICE_LOOKUP}
    )
예제 #11
0
 def test_xpi_for_multiple_platforms(self):
     platforms = [Platform.objects.get(pk=amo.PLATFORM_LINUX.id),
                  Platform.objects.get(pk=amo.PLATFORM_MAC.id)]
     addon = Addon.from_upload(self.get_upload('extension.xpi'),
                               platforms)
     v = addon.versions.get()
     eq_(sorted([f.platform.id for f in v.all_files]),
         sorted([p.id for p in platforms]))
예제 #12
0
파일: views.py 프로젝트: chusiang/zamboni
def manifest(request):

    form = forms.NewWebappForm(request.POST or None, request=request)

    features_form = forms.AppFeaturesForm(request.POST or None)
    features_form_valid = (True if not waffle.switch_is_active('buchets')
                           else features_form.is_valid())

    if (request.method == 'POST' and form.is_valid()
        and features_form_valid):

        with transaction.commit_on_success():

            addon = Addon.from_upload(
                form.cleaned_data['upload'],
                [Platform.objects.get(id=amo.PLATFORM_ALL.id)],
                is_packaged=form.is_packaged())

            # Set the device type.
            for device in form.get_devices():
                addon.addondevicetype_set.get_or_create(
                    device_type=device.id)

            # Set the premium type, only bother if it's not free.
            premium = form.get_paid()
            if premium:
                addon.update(premium_type=premium)

            if addon.has_icon_in_manifest():
                # Fetch the icon, do polling.
                addon.update(icon_type='image/png')
            else:
                # In this case there is no need to do any polling.
                addon.update(icon_type='')

            AddonUser(addon=addon, user=request.amo_user).save()
            # Checking it once. Checking it twice.
            AppSubmissionChecklist.objects.create(addon=addon, terms=True,
                                                  manifest=True)

            # Create feature profile.
            if waffle.switch_is_active('buchets'):
                addon.current_version.features.update(
                    **features_form.cleaned_data)

        # Call task outside of `commit_on_success` to avoid it running before
        # the transaction is committed and not finding the app.
        tasks.fetch_icon.delay(addon)

        return redirect('submit.app.details', addon.app_slug)

    return jingo.render(request, 'submit/manifest.html', {
        'step': 'manifest',
        'features_form': features_form,
        'form': form,
        'DEVICE_LOOKUP': DEVICE_LOOKUP
    })
예제 #13
0
def manifest(request):

    form = forms.NewWebappForm(request.POST or None, request=request)

    features_form = forms.AppFeaturesForm(request.POST or None)
    features_form_valid = features_form.is_valid()

    if (request.method == 'POST' and form.is_valid() and features_form_valid):

        with transaction.commit_on_success():

            addon = Addon.from_upload(
                form.cleaned_data['upload'],
                [Platform.objects.get(id=amo.PLATFORM_ALL.id)],
                is_packaged=form.is_packaged())

            # Set the device type.
            for device in form.get_devices():
                addon.addondevicetype_set.get_or_create(device_type=device.id)

            # Set the premium type, only bother if it's not free.
            premium = form.get_paid()
            if premium:
                addon.update(premium_type=premium)

            if addon.has_icon_in_manifest():
                # Fetch the icon, do polling.
                addon.update(icon_type='image/png')
            else:
                # In this case there is no need to do any polling.
                addon.update(icon_type='')

            AddonUser(addon=addon, user=request.amo_user).save()
            # Checking it once. Checking it twice.
            AppSubmissionChecklist.objects.create(addon=addon,
                                                  terms=True,
                                                  manifest=True,
                                                  details=False)

            # Create feature profile.
            addon.current_version.features.update(**features_form.cleaned_data)

        # Call task outside of `commit_on_success` to avoid it running before
        # the transaction is committed and not finding the app.
        tasks.fetch_icon.delay(addon)

        return redirect('submit.app.details', addon.app_slug)

    return render(
        request, 'submit/manifest.html', {
            'step': 'manifest',
            'features_form': features_form,
            'form': form,
            'DEVICE_LOOKUP': DEVICE_LOOKUP
        })
예제 #14
0
 def test_search_attributes(self):
     addon = Addon.from_upload(self.get_upload('search.xml'),
                               [self.platform])
     eq_(addon.name, 'search tool')
     eq_(addon.guid, None)
     eq_(addon.type, amo.ADDON_SEARCH)
     eq_(addon.status, amo.STATUS_NULL)
     eq_(addon.homepage, None)
     eq_(addon.description, None)
     eq_(addon.slug, 'search-tool')
     eq_(addon.summary, 'Search Engine for Firefox')
예제 #15
0
 def test_xpi_attributes(self):
     addon = Addon.from_upload(self.get_upload('extension.xpi'),
                               [self.platform])
     eq_(addon.name, 'xpi name')
     eq_(addon.guid, 'guid@xpi')
     eq_(addon.type, amo.ADDON_EXTENSION)
     eq_(addon.status, amo.STATUS_NULL)
     eq_(addon.homepage, 'http://homepage.com')
     eq_(addon.summary, 'xpi description')
     eq_(addon.description, None)
     eq_(addon.slug, 'xpi-name')
예제 #16
0
파일: views.py 프로젝트: exezaid/zamboni
def submit_addon(request, step):
    if DEV_AGREEMENT_COOKIE not in request.COOKIES:
        return redirect('devhub.submit.1')
    form = forms.NewAddonForm(request.POST or None)
    if request.method == 'POST':
        if form.is_valid():
            data = form.cleaned_data
            addon = Addon.from_upload(data['upload'], data['platforms'])
            AddonUser(addon=addon, user=request.amo_user).save()
            SubmitStep.objects.create(addon=addon, step=3)
            return redirect('devhub.submit.3', addon.slug)
    return jingo.render(request, 'devhub/addons/submit/upload.html',
                        {'step': step, 'new_addon_form': form})
예제 #17
0
def manifest(request):

    form = forms.NewWebappForm(request.POST or None, request=request)

    features_form = forms.AppFeaturesForm(request.POST or None)
    features_form_valid = features_form.is_valid()

    if request.method == "POST" and form.is_valid() and features_form_valid:

        with transaction.commit_on_success():

            addon = Addon.from_upload(
                form.cleaned_data["upload"],
                [Platform.objects.get(id=amo.PLATFORM_ALL.id)],
                is_packaged=form.is_packaged(),
            )

            # Set the device type.
            for device in form.get_devices():
                addon.addondevicetype_set.get_or_create(device_type=device.id)

            # Set the premium type, only bother if it's not free.
            premium = form.get_paid()
            if premium:
                addon.update(premium_type=premium)

            if addon.has_icon_in_manifest():
                # Fetch the icon, do polling.
                addon.update(icon_type="image/png")
            else:
                # In this case there is no need to do any polling.
                addon.update(icon_type="")

            AddonUser(addon=addon, user=request.amo_user).save()
            # Checking it once. Checking it twice.
            AppSubmissionChecklist.objects.create(addon=addon, terms=True, manifest=True, details=False)

            # Create feature profile.
            addon.current_version.features.update(**features_form.cleaned_data)

        # Call task outside of `commit_on_success` to avoid it running before
        # the transaction is committed and not finding the app.
        tasks.fetch_icon.delay(addon)

        return redirect("submit.app.details", addon.app_slug)

    return render(
        request,
        "submit/manifest.html",
        {"step": "manifest", "features_form": features_form, "form": form, "DEVICE_LOOKUP": DEVICE_LOOKUP},
    )
예제 #18
0
def submit_addon(request, step):
    if DEV_AGREEMENT_COOKIE not in request.COOKIES:
        return redirect('devhub.submit.1')
    form = forms.NewAddonForm(request.POST or None)
    if request.method == 'POST':
        if form.is_valid():
            data = form.cleaned_data
            p = (list(data['desktop_platforms']) +
                 list(data['mobile_platforms']))
            addon = Addon.from_upload(data['upload'], p)
            AddonUser(addon=addon, user=request.amo_user).save()
            SubmitStep.objects.create(addon=addon, step=3)
            return redirect('devhub.submit.3', addon.slug)
    return jingo.render(request, 'devhub/addons/submit/upload.html',
                        {'step': step, 'new_addon_form': form})
예제 #19
0
파일: resources.py 프로젝트: atsay/zamboni
    def obj_create(self, bundle, request, **kwargs):
        form = UploadForm(bundle.data)

        if not form.is_valid():
            raise self.form_errors(form)

        if not (OwnerAuthorization().is_authorized(request, object=form.obj)):
            raise ImmediateHttpResponse(response=http.HttpForbidden())

        plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)]

        # Create app, user and fetch the icon.
        bundle.obj = Addon.from_upload(form.obj, plats, is_packaged=form.is_packaged)
        AddonUser(addon=bundle.obj, user=request.amo_user).save()

        self._icons_and_images(bundle.obj)

        log.info("App created: %s" % bundle.obj.pk)
        return bundle
예제 #20
0
    def obj_create(self, bundle, request, **kwargs):
        form = UploadForm(bundle.data)

        if not form.is_valid():
            raise self.form_errors(form)

        if not (OwnerAuthorization().is_authorized(request, object=form.obj)):
            raise ImmediateHttpResponse(response=http.HttpForbidden())

        plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)]

        # Create app, user and fetch the icon.
        bundle.obj = Addon.from_upload(form.obj,
                                       plats,
                                       is_packaged=form.is_packaged)
        AddonUser(addon=bundle.obj, user=request.amo_user).save()

        self._icons_and_images(bundle.obj)
        record_action('app-submitted', request, {'app-id': bundle.obj.pk})

        log.info('App created: %s' % bundle.obj.pk)
        return bundle
예제 #21
0
def manifest(request):
    form = forms.NewWebappForm(request.POST or None)

    if request.method == 'POST' and form.is_valid():
        addon = Addon.from_upload(
            form.cleaned_data['upload'],
            [Platform.objects.get(id=amo.PLATFORM_ALL.id)],
            is_packaged=form.is_packaged())

        # Set the device type.
        for device in form.get_devices():
            addon.addondevicetype_set.get_or_create(device_type=device.id)

        # Set the premium type, only bother if it's not free.
        premium = form.get_paid()
        if premium:
            addon.update(premium_type=premium)

        if addon.has_icon_in_manifest():
            # Fetch the icon, do polling.
            addon.update(icon_type='image/png')
            tasks.fetch_icon.delay(addon)
        else:
            # In this case there is no need to do any polling.
            addon.update(icon_type='')

        AddonUser(addon=addon, user=request.amo_user).save()
        # Checking it once. Checking it twice.
        AppSubmissionChecklist.objects.create(addon=addon, terms=True,
                                              manifest=True)

        return redirect('submit.app.details', addon.app_slug)

    return jingo.render(request, 'submit/manifest.html', {
        'step': 'manifest',
        'form': form,
        'DEVICE_LOOKUP': DEVICE_LOOKUP
    })
예제 #22
0
    def obj_create(self, bundle, request, **kwargs):
        form = UploadForm(bundle.data)

        if not request.amo_user.read_dev_agreement:
            log.info(u"Attempt to use API without dev agreement: %s" % request.amo_user.pk)
            raise http_error(http.HttpUnauthorized, "Terms of service not accepted.")

        if not form.is_valid():
            raise self.form_errors(form)

        if not (OwnerAuthorization().is_authorized(request, object=form.obj)):
            raise http_error(http.HttpForbidden, "You do not own that app.")

        plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)]

        # Create app, user and fetch the icon.
        bundle.obj = Addon.from_upload(form.obj, plats, is_packaged=form.is_packaged)
        AddonUser(addon=bundle.obj, user=request.amo_user).save()

        self._icons_and_images(bundle.obj)
        record_action("app-submitted", request, {"app-id": bundle.obj.pk})

        log.info("App created: %s" % bundle.obj.pk)
        return bundle
예제 #23
0
파일: tasks.py 프로젝트: zzdjk6/zamboni
                    user__email=settings.LANGPACK_OWNER_EMAIL).exists()):
                log.info('[@None] Skipping language pack "%s": '
                         'not owned by %s' %
                         (xpi, settings.LANGPACK_OWNER_EMAIL))
                continue

            version = Version.from_upload(upload, addon, PLATFORMS)
            log.info('[@None] Updating language pack "%s" to version %s' %
                     (xpi, data['version']))
        else:
            if amo.VERSION_BETA.search(data['version']):
                log.error('[@None] Not creating beta version %s for new "%s" '
                          'language pack' % (data['version'], xpi))
                continue

            addon = Addon.from_upload(upload, PLATFORMS)
            AddonUser(addon=addon, user=owner).save()
            version = addon.versions.get()

            addon.status = amo.STATUS_PUBLIC
            if addon.default_locale.lower() == lang.lower():
                addon.target_locale = addon.default_locale

            addon.save()

            log.info('[@None] Creating new "%s" language pack, version %s' %
                     (xpi, data['version']))

        # Version.from_upload will do this automatically, but only
        # if the add-on is already public, which it may not be in
        # the case of new add-ons
예제 #24
0
 def test_blacklisted_guid(self):
     BlacklistedGuid.objects.create(guid='guid@xpi')
     with self.assertRaises(forms.ValidationError) as e:
         Addon.from_upload(self.get_upload('extension.xpi'),
                           [self.platform])
     eq_(e.exception.messages, ['Duplicate UUID found.'])
예제 #25
0
 def test_no_homepage(self):
     addon = Addon.from_upload(self.get_upload('extension-no-homepage.xpi'),
                               [self.platform])
     eq_(addon.homepage, None)
예제 #26
0
                         .exists()):
                log.info('[@None] Skipping language pack "%s": '
                         'not owned by %s' % (xpi,
                                              settings.LANGPACK_OWNER_EMAIL))
                continue

            version = Version.from_upload(upload, addon, PLATFORMS)
            log.info('[@None] Updating language pack "%s" to version %s'
                     % (xpi, data['version']))
        else:
            if amo.VERSION_BETA.search(data['version']):
                log.error('[@None] Not creating beta version %s for new "%s" '
                          'language pack' % (data['version'], xpi))
                continue

            addon = Addon.from_upload(upload, PLATFORMS)
            AddonUser(addon=addon, user=owner).save()
            version = addon.versions.get()

            addon.status = amo.STATUS_PUBLIC
            if addon.default_locale.lower() == lang.lower():
                addon.target_locale = addon.default_locale

            addon.save()

            log.info('[@None] Creating new "%s" language pack, version %s'
                     % (xpi, data['version']))

        # Version.from_upload will do this automatically, but only
        # if the add-on is already public, which it may not be in
        # the case of new add-ons
예제 #27
0
파일: tasks.py 프로젝트: satdav/olympia
            if is_beta:
                log.error('[@None] Not creating beta version {0} for new '
                          '"{1}" language pack'.format(data['version'], xpi))
                return

            if (Addon.objects.filter(
                    name__localized_string=data['name']).exists()):
                data['old_name'] = data['name']
                data['name'] = u'{0} ({1})'.format(
                    data['old_name'], data['apps'][0].appdata.pretty)

                log.warning(u'[@None] Creating langpack {guid}: Add-on with '
                            u'name {old_name!r} already exists, trying '
                            u'{name!r}.'.format(**data))

            addon = Addon.from_upload(upload, [amo.PLATFORM_ALL.id], data=data)
            AddonUser(addon=addon, user=owner).save()
            version = addon.versions.get()

            addon.status = amo.STATUS_PUBLIC
            if addon.default_locale.lower() == lang.lower():
                addon.target_locale = addon.default_locale

            addon.save()

            log.info(
                '[@None] Created new "{0}" language pack, version {1}'.format(
                    xpi, data['version']))

        if not is_beta:
            # Not `version.files.update`, because we need to trigger save
예제 #28
0
파일: tasks.py 프로젝트: Nolski/olympia
            if is_beta:
                log.error('[@None] Not creating beta version {0} for new '
                          '"{1}" language pack'.format(data['version'], xpi))
                return

            if (Addon.objects.filter(name__localized_string=data['name'])
                    .exists()):
                data['old_name'] = data['name']
                data['name'] = u'{0} ({1})'.format(
                    data['old_name'], data['apps'][0].appdata.pretty)

                log.warning(u'[@None] Creating langpack {guid}: Add-on with '
                            u'name {old_name!r} already exists, trying '
                            u'{name!r}.'.format(**data))

            addon = Addon.from_upload(upload, [amo.PLATFORM_ALL.id], data=data)
            AddonUser(addon=addon, user=owner).save()
            version = addon.versions.get()

            addon.status = amo.STATUS_PUBLIC
            if addon.default_locale.lower() == lang.lower():
                addon.target_locale = addon.default_locale

            addon.save()

            log.info('[@None] Created new "{0}" language pack, version {1}'
                     .format(xpi, data['version']))

        if not is_beta:
            # Not `version.files.update`, because we need to trigger save
            # hooks.