def version_list(request, addon, beta=False): qs = _version_list_qs(addon, beta=beta) versions = amo.utils.paginate(request, qs, PER_PAGE) versions.object_list = list(versions.object_list) Version.transformer(versions.object_list) return render(request, 'versions/version_list.html', { 'addon': addon, 'beta': beta, 'versions': versions})
def test_status_beta(self): # Check that the add-on + files are in the public status. assert self.addon.status == amo.STATUS_PUBLIC assert File.objects.filter(version=self.current)[0].status == ( amo.STATUS_PUBLIC) # Create a new under review version with a pending file. upload = self.get_upload('extension-0.2.xpi') new_version = Version.from_upload(upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) new_version.files.all()[0].update(status=amo.STATUS_PENDING) # Create a beta version. upload = self.get_upload('extension-0.2b1.xpi') beta_version = Version.from_upload(upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED, is_beta=True) # Check that it doesn't modify the public status. assert self.addon.status == amo.STATUS_PUBLIC assert File.objects.filter(version=self.current)[0].status == ( amo.STATUS_PUBLIC) # Check that the file created with the beta version is in beta status. assert File.objects.filter(version=beta_version)[0].status == ( amo.STATUS_BETA) # Check that the previously uploaded version is still pending. assert File.objects.filter(version=new_version)[0].status == ( amo.STATUS_PENDING)
def fake_version_object(self, obj, data, channel): if data: version = Version( addon=obj, id=data['id'], reviewed=self.handle_date(data['reviewed']), version=data['version'], channel=channel) version.all_files = [ File( id=file_['id'], created=self.handle_date(file_['created']), hash=file_['hash'], filename=file_['filename'], platform=file_['platform'], size=file_['size'], status=file_['status'], version=version) for file_ in data.get('files', []) ] # In ES we store integers for the appversion info, we need to # convert it back to strings. compatible_apps = {} for app_id, compat_dict in data.get('compatible_apps', {}).items(): app_name = APPS_ALL[int(app_id)] compatible_apps[app_name] = ApplicationsVersions( min=AppVersion(version=compat_dict.get('min_human', '')), max=AppVersion(version=compat_dict.get('max_human', ''))) version.compatible_apps = compatible_apps else: version = None return version
def test_status(self): self.current.files.all().update(status=amo.STATUS_AWAITING_REVIEW) Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED, parsed_data=self.dummy_parsed_data) assert File.objects.filter(version=self.current)[0].status == ( amo.STATUS_DISABLED)
def version_list(request, addon, template, beta=False): status_list = (amo.STATUS_BETA,) if beta else amo.VALID_STATUSES qs = addon.versions.filter(files__status__in=status_list).distinct().order_by("-created") versions = amo.utils.paginate(request, qs, PER_PAGE) versions.object_list = list(versions.object_list) Version.transformer(versions.object_list) return render(request, template, {"addon": addon, "beta": beta, "versions": versions})
def version_list(request, addon, template, beta=False): status_list = (amo.STATUS_BETA,) if beta else amo.VALID_FILE_STATUSES qs = (addon.versions.filter(files__status__in=status_list) .distinct().order_by('-created')) versions = amo.utils.paginate(request, qs, PER_PAGE) versions.object_list = list(versions.object_list) Version.transformer(versions.object_list) return render(request, template, {'addon': addon, 'beta': beta, 'versions': versions})
def create_version(self, license=None): data = self.cleaned_data v = Version(addon=self.addon, license=license, version=data['version'], releasenotes=data['release_notes']) v.save() amo.log(amo.LOG.ADD_VERSION, v.addon, v) self._save_apps(v) self._save_file(v) return v
def test_version_status(): addon = Addon() version = Version() version.all_files = [File(status=amo.STATUS_PUBLIC), File(status=amo.STATUS_AWAITING_REVIEW)] assert u'Approved,Awaiting Review' == ( jinja_helpers.version_status(addon, version)) version.all_files = [File(status=amo.STATUS_AWAITING_REVIEW)] assert u'Awaiting Review' == jinja_helpers.version_status(addon, version)
def test_version_status(): addon = Addon() version = Version() version.all_files = [File(status=amo.STATUS_PUBLIC), File(status=amo.STATUS_UNREVIEWED)] assert u'Fully Reviewed,Awaiting Review' == ( helpers.version_status(addon, version)) version.all_files = [File(status=amo.STATUS_UNREVIEWED)] assert u'Awaiting Review' == helpers.version_status(addon, version)
def _extra_version_and_file(self, status): version = Version.objects.get(id=81551) version_two = Version(addon=self.addon, license=version.license, version='1.2.3') version_two.save() file_two = File(status=status, version=version_two) file_two.save() return version_two, file_two
def create_file(self, **kwargs): addon = Addon() addon.save() ver = Version(version='0.1') ver.addon = addon ver.save() f = File(**kwargs) f.version = ver f.save() return f
def test_version_number(self): parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload( self.upload, self.addon, [self.selected_app], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) assert version.version == self.now
def test_file_not_multi_package(self): parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) files = version.all_files assert not files[0].is_multi_package
def test_file_name(self): parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) files = version.all_files assert files[0].filename == u'delicious_bookmarks-0.1-fx-mac.xpi'
def create_version_for_upload(addon, upload): fileupload_exists = addon.fileupload_set.filter( created__gt=upload.created, version=upload.version).exists() version_exists = Version.unfiltered.filter( addon=addon, version=upload.version).exists() if (fileupload_exists or version_exists): log.info('Skipping Version creation for {upload_uuid} that would ' ' cause duplicate version'.format(upload_uuid=upload.uuid)) else: # Import loop. from olympia.devhub.views import auto_sign_version log.info('Creating version for {upload_uuid} that passed ' 'validation'.format(upload_uuid=upload.uuid)) beta = (addon.is_listed and bool(upload.version) and is_beta(upload.version)) version = Version.from_upload( upload, addon, [amo.PLATFORM_ALL.id], is_beta=beta) # The add-on's status will be STATUS_NULL when its first version is # created because the version has no files when it gets added and it # gets flagged as invalid. We need to manually set the status. # # Note: this assumes the developer wants a full review. This makes # sense for now because this function is only called from # submit_file(), which is itself only called from the signing API, # which only supports unlisted add-ons, and unlisted add-ons are # supposed to automatically be set as fully reviewed once signed. if addon.status == amo.STATUS_NULL: addon.update(status=amo.STATUS_NOMINATED) auto_sign_version(version, is_beta=version.is_beta)
def create_version_for_upload(addon, upload): fileupload_exists = addon.fileupload_set.filter( created__gt=upload.created, version=upload.version).exists() version_exists = Version.unfiltered.filter( addon=addon, version=upload.version).exists() if (fileupload_exists or version_exists): log.info('Skipping Version creation for {upload_uuid} that would ' ' cause duplicate version'.format(upload_uuid=upload.uuid)) else: # Import loop. from olympia.devhub.views import auto_sign_version log.info('Creating version for {upload_uuid} that passed ' 'validation'.format(upload_uuid=upload.uuid)) beta = bool(upload.version) and is_beta(upload.version) version = Version.from_upload( upload, addon, [amo.PLATFORM_ALL.id], is_beta=beta) # The add-on's status will be STATUS_NULL when its first version is # created because the version has no files when it gets added and it # gets flagged as invalid. We need to manually set the status. # TODO: Handle sideload add-ons. This assumes the user wants a prelim # review since listed and sideload aren't supported for creation yet. if addon.status == amo.STATUS_NULL: addon.update(status=amo.STATUS_LITE) auto_sign_version(version, is_beta=version.is_beta)
def test_android_creates_platform_files(self): version = Version.from_upload(self.upload, self.addon, [amo.PLATFORM_ANDROID.id], amo.RELEASE_CHANNEL_LISTED) files = version.all_files assert sorted(amo.PLATFORMS[f.platform].shortname for f in files) == ( ['android'])
def test_carry_over_license_no_version(self): self.addon.versions.all().delete() version = Version.from_upload( self.upload, self.addon, [self.selected_app], amo.RELEASE_CHANNEL_LISTED, parsed_data=self.dummy_parsed_data) assert version.license_id is None
def test_app_versions(self): version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) assert amo.FIREFOX in version.compatible_apps app = version.compatible_apps[amo.FIREFOX] assert app.min.version == '3.0' assert app.max.version == '3.6.*'
def create_version_for_upload(addon, upload, channel): """Note this function is only used for API uploads.""" fileupload_exists = addon.fileupload_set.filter( created__gt=upload.created, version=upload.version).exists() version_exists = Version.unfiltered.filter( addon=addon, version=upload.version).exists() if (fileupload_exists or version_exists): log.info('Skipping Version creation for {upload_uuid} that would ' ' cause duplicate version'.format(upload_uuid=upload.uuid)) else: # Import loop. from olympia.devhub.utils import add_dynamic_theme_tag from olympia.devhub.views import auto_sign_version log.info('Creating version for {upload_uuid} that passed ' 'validation'.format(upload_uuid=upload.uuid)) # Note: if we somehow managed to get here with an invalid add-on, # parse_addon() will raise ValidationError and the task will fail # loudly in sentry. parsed_data = parse_addon(upload, addon, user=upload.user) version = Version.from_upload( upload, addon, [x[0] for x in amo.APPS_CHOICES], channel, parsed_data=parsed_data) # The add-on's status will be STATUS_NULL when its first version is # created because the version has no files when it gets added and it # gets flagged as invalid. We need to manually set the status. if (addon.status == amo.STATUS_NULL and channel == amo.RELEASE_CHANNEL_LISTED): addon.update(status=amo.STATUS_NOMINATED) auto_sign_version(version) add_dynamic_theme_tag(version)
def create_version_for_upload(addon, upload, channel): """Note this function is only used for API uploads.""" fileupload_exists = addon.fileupload_set.filter( created__gt=upload.created, version=upload.version).exists() version_exists = Version.unfiltered.filter( addon=addon, version=upload.version).exists() if (fileupload_exists or version_exists): log.info('Skipping Version creation for {upload_uuid} that would ' ' cause duplicate version'.format(upload_uuid=upload.uuid)) else: # Import loop. from olympia.devhub.views import auto_sign_version log.info('Creating version for {upload_uuid} that passed ' 'validation'.format(upload_uuid=upload.uuid)) beta = bool(upload.version) and is_beta(upload.version) version = Version.from_upload( upload, addon, [amo.PLATFORM_ALL.id], channel, is_beta=beta) # The add-on's status will be STATUS_NULL when its first version is # created because the version has no files when it gets added and it # gets flagged as invalid. We need to manually set the status. if (addon.status == amo.STATUS_NULL and channel == amo.RELEASE_CHANNEL_LISTED): addon.update(status=amo.STATUS_NOMINATED) auto_sign_version(version, is_beta=version.is_beta)
def migrate_legacy_dictionary_to_webextension(addon): """Migrate a single legacy dictionary to webextension format, creating a new package from the current_version, faking an upload to create a new Version instance.""" user = UserProfile.objects.get(pk=settings.TASK_USER_ID) now = datetime.now() # Wrap zip in FileUpload for Version.from_upload() to consume. upload = FileUpload.objects.create( user=user, valid=True) destination = os.path.join( user_media_path('addons'), 'temp', uuid.uuid4().hex + '.xpi') target_language = build_webext_dictionary_from_legacy(addon, destination) if not addon.target_locale: addon.update(target_locale=target_language) upload.update(path=destination) parsed_data = parse_addon(upload, addon=addon, user=user) # Create version. # WebExtension dictionaries are only compatible with Firefox Desktop # Firefox for Android uses the OS spellchecking. version = Version.from_upload( upload, addon, selected_apps=[amo.FIREFOX.id], channel=amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) activity.log_create(amo.LOG.ADD_VERSION, version, addon, user=user) # Sign the file, and set it to public. That should automatically set # current_version to the version we created. file_ = version.all_files[0] sign_file(file_) file_.update(datestatuschanged=now, reviewed=now, status=amo.STATUS_PUBLIC)
def test_mozilla_signed_extension(self): self.dummy_parsed_data['is_mozilla_signed_extension'] = True version = Version.from_upload( self.upload, self.addon, [self.selected_app], amo.RELEASE_CHANNEL_LISTED, parsed_data=self.dummy_parsed_data) assert version.is_mozilla_signed assert version.approval_notes == (u'This version has been signed with ' u'Mozilla internal certificate.')
def test_file_platform_is_always_all(self): parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) files = version.all_files assert len(files) == 1 assert files[0].platform == amo.PLATFORM_ALL.id
def test_new_version_is_10s_compatible_no_feature_compat_previously(self): assert not self.addon.feature_compatibility.pk self.upload = self.get_upload('multiprocess_compatible_extension.xpi') version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) assert version.pk assert self.addon.feature_compatibility.pk assert self.addon.feature_compatibility.e10s == amo.E10S_COMPATIBLE
def test_app_versions(self): parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) assert amo.FIREFOX in version.compatible_apps app = version.compatible_apps[amo.FIREFOX] assert app.min.version == '3.0' assert app.max.version == '3.6.*'
def test_new_version_while_public( self, generate_static_theme_preview_mock): self.addon = addon_factory(type=amo.ADDON_STATICTHEME) parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload( self.upload, self.addon, [], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) assert len(version.all_files) == 1 assert generate_static_theme_preview_mock.call_count == 1
def test_file_name(self): parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload( self.upload, self.addon, [self.selected_app], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) files = version.all_files assert files[0].filename == ( u'delicious_bookmarks-%s.xml' % self.now)
def test_version_log_transformer(self): addon = Addon.objects.get() version = addon.latest_version amo.log(amo.LOG.REJECT_VERSION, addon, version, user=self.request.user) version_two = Version(addon=addon, license=version.license, version='1.2.3') version_two.save() amo.log(amo.LOG.REJECT_VERSION, addon, version_two, user=self.request.user) versions = (Version.objects.filter(addon=addon).order_by('-created') .transform(Version.transformer_activity)) eq_(len(versions[0].all_activity), 1) eq_(len(versions[1].all_activity), 1)
def test_track_upload_time(self): # Set created time back (just for sanity) otherwise the delta # would be in the microsecond range. self.upload.update(created=datetime.now() - timedelta(days=1)) mock_timing_path = 'olympia.versions.models.statsd.timing' with mock.patch(mock_timing_path) as mock_timing: Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) upload_start = utc_millesecs_from_epoch(self.upload.created) now = utc_millesecs_from_epoch() rough_delta = now - upload_start actual_delta = mock_timing.call_args[0][1] fuzz = 2000 # 2 seconds assert (actual_delta >= (rough_delta - fuzz) and actual_delta <= (rough_delta + fuzz))
def test_file_name(self): version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) files = version.all_files assert files[0].filename == ( u'delicious_bookmarks-%s.xml' % self.now)
def test_file_not_multi_package(self): version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) files = version.all_files assert not files[0].is_multi_package
def test_version_number(self): version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) assert version.version == self.now
if addon: if addon.versions.filter(version=data['version']).exists(): log.info( '[@None] Version {0} of "{1}" language pack exists'.format( data['version'], xpi)) return if not addon.addonuser_set.filter(user=owner).exists(): log.info('[@None] Skipping language pack "{0}": ' 'not owned by {1}'.format( xpi, settings.LANGPACK_OWNER_EMAIL)) return version = Version.from_upload(upload, addon, [amo.PLATFORM_ALL.id], is_beta=is_beta) log.info( '[@None] Updated language pack "{0}" to version {1}'.format( xpi, data['version'])) else: 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(
def create_new_version(): return Version.from_upload(upload, addon, [amo.FIREFOX.id], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data)
def get_url(self, obj): # Addon.get_url_path() wants current_version to exist, but that's just # a safeguard. We don't care and don't want to fetch the current # version field to improve perf, so give it a fake one. obj._current_version = Version() return absolutify(obj.get_url_path())
def add_static_theme_from_lwt(lwt): from olympia.activity.models import AddonLog # Try to handle LWT with no authors author = (lwt.listed_authors or [_get_lwt_default_author()])[0] # Wrap zip in FileUpload for Addon/Version from_upload to consume. upload = FileUpload.objects.create( user=author, valid=True) destination = os.path.join( user_media_path('addons'), 'temp', uuid.uuid4().hex + '.xpi') build_static_theme_xpi_from_lwt(lwt, destination) upload.update(path=destination) # Create addon + version parsed_data = parse_addon(upload, user=author) addon = Addon.initialize_addon_from_upload( parsed_data, upload, amo.RELEASE_CHANNEL_LISTED, author) addon_updates = {} # Version.from_upload sorts out platforms for us. version = Version.from_upload( upload, addon, platforms=None, channel=amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) # Set category static_theme_categories = CATEGORIES.get(amo.FIREFOX.id, []).get( amo.ADDON_STATICTHEME, []) lwt_category = (lwt.categories.all() or [None])[0] # lwt only have 1 cat. lwt_category_slug = lwt_category.slug if lwt_category else 'other' static_category = static_theme_categories.get( lwt_category_slug, static_theme_categories.get('other')) AddonCategory.objects.create( addon=addon, category=Category.from_static_category(static_category, True)) # Set license lwt_license = PERSONA_LICENSES_IDS.get( lwt.persona.license, LICENSE_COPYRIGHT_AR) # default to full copyright static_license = License.objects.get(builtin=lwt_license.builtin) version.update(license=static_license) # Set tags for addon_tag in AddonTag.objects.filter(addon=lwt): AddonTag.objects.create(addon=addon, tag=addon_tag.tag) # Steal the ratings (even with soft delete they'll be deleted anyway) addon_updates.update( average_rating=lwt.average_rating, bayesian_rating=lwt.bayesian_rating, total_ratings=lwt.total_ratings, text_ratings_count=lwt.text_ratings_count) Rating.unfiltered.filter(addon=lwt).update(addon=addon, version=version) # Modify the activity log entry too. rating_activity_log_ids = [ l.id for l in amo.LOG if getattr(l, 'action_class', '') == 'review'] addonlog_qs = AddonLog.objects.filter( addon=lwt, activity_log__action__in=rating_activity_log_ids) [alog.transfer(addon) for alog in addonlog_qs.iterator()] # Copy the ADU statistics - the raw(ish) daily UpdateCounts for stats # dashboard and future update counts, and copy the summary numbers for now. migrate_theme_update_count(lwt, addon) addon_updates.update( average_daily_users=lwt.persona.popularity or 0, hotness=lwt.persona.movers or 0) # Logging activity.log_create( amo.LOG.CREATE_STATICTHEME_FROM_PERSONA, addon, user=author) # And finally sign the files (actually just one) for file_ in version.all_files: sign_file(file_) file_.update( datestatuschanged=datetime.now(), reviewed=datetime.now(), status=amo.STATUS_PUBLIC) addon_updates['status'] = amo.STATUS_PUBLIC # set the modified and creation dates to match the original. addon_updates['created'] = lwt.created addon_updates['modified'] = lwt.modified addon.update(**addon_updates) return addon
def _get_version(self, status): v = Version() v.all_files = [mock.Mock()] v.all_files[0].status = status return v
def test_carry_over_old_license(self): version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) assert version.license_id == self.addon.current_version.license_id
def fake_object(self, data): """Create a fake instance of Addon and related models from ES data.""" obj = Addon(id=data['id'], slug=data['slug'], is_listed=True) # Attach base attributes that have the same name/format in ES and in # the model. self._attach_fields( obj, data, ('average_daily_users', 'bayesian_rating', 'created', 'default_locale', 'guid', 'hotness', 'icon_type', 'is_listed', 'last_updated', 'modified', 'public_stats', 'slug', 'status', 'type', 'weekly_downloads')) # Temporary hack to make sure all add-ons have a modified date when # serializing, to avoid errors when calling get_icon_url(). # Remove once all add-ons have been reindexed at least once since the # addition of `modified` in the mapping. if obj.modified is None: obj.modified = obj.created # Attach attributes that do not have the same name/format in ES. obj.tag_list = data['tags'] obj.disabled_by_user = data['is_disabled'] # Not accurate, but enough. # Categories are annoying, skip them for now. We probably need to start # declaring them in the code to properly handle translations etc if we # want to display them in search results. obj.all_categories = [] # Attach translations (they require special treatment). self._attach_translations(obj, data, self.translated_fields) # Attach related models (also faking them). data_version = data.get('current_version') if data_version: obj._current_version = Version(addon=obj, id=data_version['id'], reviewed=self.handle_date( data_version['reviewed']), version=data_version['version']) data_files = data_version.get('files', []) obj._current_version.all_files = [ File(id=file_['id'], created=self.handle_date(file_['created']), hash=file_['hash'], filename=file_['filename'], platform=file_['platform'], size=file_['size'], status=file_['status'], version=obj._current_version) for file_ in data_files ] # In ES we store integers for the appversion info, we need to # convert it back to strings. compatible_apps = {} for app_id, compat_dict in data['appversion'].items(): app_name = APPS_ALL[int(app_id)] compatible_apps[app_name] = ApplicationsVersions( min=AppVersion(version=compat_dict.get('min_human', '')), max=AppVersion(version=compat_dict.get('max_human', ''))) obj._current_version.compatible_apps = compatible_apps if data['type'] == amo.ADDON_PERSONA: persona_data = data.get('persona') if persona_data: obj.persona = Persona( addon=obj, accentcolor=persona_data['accentcolor'], display_username=persona_data['author'], header=persona_data['header'], footer=persona_data['footer'], persona_id=1 if persona_data['is_new'] else None, textcolor=persona_data['textcolor']) else: # Sadly, https://code.djangoproject.com/ticket/14368 prevents # us from setting obj.persona = None. This is fixed in # Django 1.9, but in the meantime, work around it by creating # a Persona instance with a custom attribute indicating that # it should not be used. obj.persona = Persona() obj.persona._broken = True return obj
def add_static_theme_from_lwt(lwt): from olympia.activity.models import AddonLog timer = StopWatch( 'addons.tasks.migrate_lwts_to_static_theme.add_from_lwt.') timer.start() olympia.core.set_user(UserProfile.objects.get(pk=settings.TASK_USER_ID)) # Try to handle LWT with no authors author = (lwt.listed_authors or [_get_lwt_default_author()])[0] # Wrap zip in FileUpload for Addon/Version from_upload to consume. upload = FileUpload.objects.create(user=author, valid=True) filename = uuid.uuid4().hex + '.xpi' destination = os.path.join(user_media_path('addons'), 'temp', filename) build_static_theme_xpi_from_lwt(lwt, destination) upload.update(path=destination, name=filename) timer.log_interval('1.build_xpi') # Create addon + version parsed_data = parse_addon(upload, user=author) timer.log_interval('2a.parse_addon') addon = Addon.initialize_addon_from_upload(parsed_data, upload, amo.RELEASE_CHANNEL_LISTED, author) addon_updates = {} timer.log_interval('2b.initialize_addon') # static themes are only compatible with Firefox at the moment, # not Android version = Version.from_upload(upload, addon, selected_apps=[amo.FIREFOX.id], channel=amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) timer.log_interval('3.initialize_version') # Set category lwt_category = (lwt.categories.all() or [None])[0] # lwt only have 1 cat. lwt_category_slug = lwt_category.slug if lwt_category else 'other' for app, type_dict in CATEGORIES.items(): static_theme_categories = type_dict.get(amo.ADDON_STATICTHEME, []) static_category = static_theme_categories.get( lwt_category_slug, static_theme_categories.get('other')) AddonCategory.objects.create(addon=addon, category=Category.from_static_category( static_category, True)) timer.log_interval('4.set_categories') # Set license lwt_license = PERSONA_LICENSES_IDS.get( lwt.persona.license, LICENSE_COPYRIGHT_AR) # default to full copyright static_license = License.objects.get(builtin=lwt_license.builtin) version.update(license=static_license) timer.log_interval('5.set_license') # Set tags for addon_tag in AddonTag.objects.filter(addon=lwt): AddonTag.objects.create(addon=addon, tag=addon_tag.tag) timer.log_interval('6.set_tags') # Steal the ratings (even with soft delete they'll be deleted anyway) addon_updates.update(average_rating=lwt.average_rating, bayesian_rating=lwt.bayesian_rating, total_ratings=lwt.total_ratings, text_ratings_count=lwt.text_ratings_count) Rating.unfiltered.filter(addon=lwt).update(addon=addon, version=version) timer.log_interval('7.move_ratings') # Replace the lwt in collections CollectionAddon.objects.filter(addon=lwt).update(addon=addon) # Modify the activity log entry too. rating_activity_log_ids = [ l.id for l in amo.LOG if getattr(l, 'action_class', '') == 'review' ] addonlog_qs = AddonLog.objects.filter( addon=lwt, activity_log__action__in=rating_activity_log_ids) [alog.transfer(addon) for alog in addonlog_qs.iterator()] timer.log_interval('8.move_activity_logs') # Copy the ADU statistics - the raw(ish) daily UpdateCounts for stats # dashboard and future update counts, and copy the average_daily_users. # hotness will be recalculated by the deliver_hotness() cron in a more # reliable way that we could do, so skip it entirely. migrate_theme_update_count(lwt, addon) addon_updates.update(average_daily_users=lwt.persona.popularity or 0, hotness=0) timer.log_interval('9.copy_statistics') # Logging activity.log_create(amo.LOG.CREATE_STATICTHEME_FROM_PERSONA, addon, user=author) # And finally sign the files (actually just one) for file_ in version.all_files: sign_file(file_) file_.update(datestatuschanged=lwt.last_updated, reviewed=datetime.now(), status=amo.STATUS_APPROVED) timer.log_interval('10.sign_files') addon_updates['status'] = amo.STATUS_APPROVED # set the modified and creation dates to match the original. addon_updates['created'] = lwt.created addon_updates['modified'] = lwt.modified addon_updates['last_updated'] = lwt.last_updated addon.update(**addon_updates) return addon
def _transformer(self, objs): Version.transformer_promoted([ promo.addon._current_version for promo in objs if promo.addon._current_version ])
owner = UserProfile.objects.get(email=settings.LANGPACK_OWNER_EMAIL) if addon: if addon.versions.filter(version=data['version']).exists(): log.info('[@None] Version {0} of "{1}" language pack exists' .format(data['version'], xpi)) return if not addon.addonuser_set.filter(user=owner).exists(): log.info('[@None] Skipping language pack "{0}": ' 'not owned by {1}'.format( xpi, settings.LANGPACK_OWNER_EMAIL)) return version = Version.from_upload(upload, addon, [amo.PLATFORM_ALL.id], amo.RELEASE_CHANNEL_LISTED, parsed_data=data) log.info('[@None] Updated language pack "{0}" to version {1}' .format(xpi, data['version'])) else: 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))
def test_carry_over_old_license(self): version = Version.from_upload(self.upload, self.addon, [self.selected_app], amo.RELEASE_CHANNEL_LISTED, parsed_data=self.dummy_parsed_data) assert version.license_id == self.addon.current_version.license_id
def test_file_platform_is_always_all(self): version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) files = version.all_files assert len(files) == 1 assert files[0].platform == amo.PLATFORM_ALL.id
def test_carry_over_license_no_version(self): self.addon.versions.all().delete() version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) assert version.license_id is None
def test_status(self): self.current.files.all().update(status=amo.STATUS_AWAITING_REVIEW) Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) assert File.objects.filter(version=self.current)[0].status == ( amo.STATUS_DISABLED)
def test_file_platform(self): version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) files = version.all_files assert len(files) == 1 assert files[0].platform == self.platform
def test_generate_filename_ja(self): f = File() f.version = Version(version='0.1.7') f.version.compatible_apps = (amo.FIREFOX, ) f.version.addon = Addon(name=u' フォクすけ といっしょ') assert f.generate_filename() == 'addon-0.1.7-fx.xpi'
def test_file_name_platform_all(self): version = Version.from_upload(self.upload, self.addon, [amo.PLATFORM_ALL.id], amo.RELEASE_CHANNEL_LISTED) files = version.all_files assert files[0].filename == u'delicious_bookmarks-0.1-fx.xpi'
def create_version(self, addon=None): from olympia.addons.models import Addon from olympia.files.models import FileUpload from olympia.files.utils import parse_addon from olympia.versions.models import Version from olympia.versions.utils import get_next_version_number version_number = '1.0' # If passing an existing add-on, we need to bump the version number # to avoid clashes, and also perform a few checks. if addon is not None: # Obviously we want an add-on with the right type. if addon.type != amo.ADDON_SITE_PERMISSION: raise ImproperlyConfigured( 'SitePermissionVersionCreator was instantiated with non ' 'site-permission add-on' ) # If the user isn't an author, something is wrong. if not addon.authors.filter(pk=self.user.pk).exists(): raise ImproperlyConfigured( 'SitePermissionVersionCreator was instantiated with a ' 'bogus addon/user' ) # Changing the origins isn't supported at the moment. latest_version = addon.find_latest_version( exclude=(), channel=amo.RELEASE_CHANNEL_UNLISTED ) previous_origins = sorted( latest_version.installorigin_set.all().values_list('origin', flat=True) ) if previous_origins != self.install_origins: raise ImproperlyConfigured( 'SitePermissionVersionCreator was instantiated with an ' 'addon that has different origins' ) version_number = get_next_version_number(addon) # Create the manifest, with more user-friendly name & description built # from install_origins/site_permissions, and then the zipfile with that # manifest inside. manifest_data = self._create_manifest(version_number) file_obj = self._create_zipfile(manifest_data) # Parse the zip we just created. The user needs to be the Mozilla User # because regular submissions of this type of add-on is forbidden to # normal users. parsed_data = parse_addon( file_obj, addon=addon, user=get_task_user(), ) with core.override_remote_addr(self.remote_addr): if addon is None: # Create the Addon instance (without a Version/File at this point). addon = Addon.initialize_addon_from_upload( data=parsed_data, upload=file_obj, channel=amo.RELEASE_CHANNEL_UNLISTED, user=self.user, ) # Create the FileUpload that will become the File+Version. upload = FileUpload.from_post( file_obj, filename=file_obj.name, size=file_obj.size, addon=addon, version=version_number, channel=amo.RELEASE_CHANNEL_UNLISTED, user=self.user, source=amo.UPLOAD_SOURCE_GENERATED, ) # And finally create the Version instance from the FileUpload. return Version.from_upload( upload, addon, amo.RELEASE_CHANNEL_UNLISTED, selected_apps=[x[0] for x in amo.APPS_CHOICES], parsed_data=parsed_data, )
def test_file_multi_package(self): version = Version.from_upload(self.get_upload('multi-package.xpi'), self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED) files = version.all_files assert files[0].is_multi_package
def test_version_number(self): parsed_data = parse_addon(self.upload, self.addon, user=mock.Mock()) version = Version.from_upload(self.upload, self.addon, [self.platform], amo.RELEASE_CHANNEL_LISTED, parsed_data=parsed_data) assert version.version == self.now
if addon: if addon.versions.filter(version=data['version']).exists(): log.info( '[@None] Version {0} of "{1}" language pack exists'.format( data['version'], xpi)) return if not addon.addonuser_set.filter(user=owner).exists(): log.info('[@None] Skipping language pack "{0}": ' 'not owned by {1}'.format( xpi, settings.LANGPACK_OWNER_EMAIL)) return version = Version.from_upload(upload, addon, [amo.PLATFORM_ALL.id], amo.RELEASE_CHANNEL_LISTED, is_beta=is_beta) log.info( '[@None] Updated language pack "{0}" to version {1}'.format( xpi, data['version'])) else: 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(