def process_public(self): """Set an add-on or a version to public.""" # Safeguard to force implementation for unlisted add-ons to completely # override this method. assert self.version.channel == amo.RELEASE_CHANNEL_LISTED # Safeguard to make sure this action is not used for content review # (it should use confirm_auto_approved instead). assert not self.content_review_only # Sign addon. use_autograph = waffle.flag_is_active(self.request, 'activate-autograph-signing') for file_ in self.files: sign_file(file_, use_autograph=use_autograph) # Hold onto the status before we change it. status = self.addon.status # Save files first, because set_addon checks to make sure there # is at least one public file or it won't make the addon public. self.set_files(amo.STATUS_PUBLIC, self.files) if self.set_addon_status: self.set_addon(status=amo.STATUS_PUBLIC) # If we've approved a webextension, add a tag identifying them as such. if any(file_.is_webextension for file_ in self.files): Tag(tag_text='firefox57').save_tag(self.addon) # If we've approved a mozilla signed add-on, add the firefox57 tag if all(file_.is_mozilla_signed_extension for file_ in self.files): Tag(tag_text='firefox57').save_tag(self.addon) # Increment approvals counter if we have a request (it means it's a # human doing the review) otherwise reset it as it's an automatic # approval. if self.request: AddonApprovalsCounter.increment_for_addon(addon=self.addon) else: AddonApprovalsCounter.reset_for_addon(addon=self.addon) self.log_action(amo.LOG.APPROVE_VERSION) template = u'%s_to_public' % self.review_type if self.review_type == 'pending': subject = u'Mozilla Add-ons: %s %s Updated' else: subject = u'Mozilla Add-ons: %s %s Approved' self.notify_email(template, subject) self.log_public_message() log.info(u'Sending email for %s' % (self.addon)) # Assign reviewer incentive scores. if self.request: ReviewerScore.award_points(self.request.user, self.addon, status, version=self.version)
def save(self): addon = self.instance persona = addon.persona data = self.cleaned_data # Update Persona-specific data. persona_data = { 'license': int(data['license']), 'accentcolor': data['accentcolor'].lstrip('#'), 'textcolor': data['textcolor'].lstrip('#'), 'author': self.request.user.username, 'display_username': self.request.user.name } changed = False for k, v in persona_data.iteritems(): if v != getattr(persona, k): changed = True setattr(persona, k, v) if changed: persona.save() if self.changed_data: amo.log(amo.LOG.EDIT_PROPERTIES, addon) self.instance.modified = datetime.now() # Update Addon-specific data. changed = ( set(self.old_tags) != data['tags'] or # Check if tags changed. self.initial['slug'] != data['slug'] or # Check if slug changed. transfield_changed('description', self.initial, data) or transfield_changed('name', self.initial, data)) if changed: # Only save if addon data changed. super(EditThemeForm, self).save() # Update tags. tags_new = data['tags'] tags_old = [slugify(t, spaces=True) for t in self.old_tags] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # Update category. if data['category'].id != self.initial['category']: addon_cat = addon.addoncategory_set.all()[0] addon_cat.category = data['category'] addon_cat.save() # Theme reupload. if not addon.is_pending(): if data['header_hash'] or data['footer_hash']: save_theme_reupload.delay(data['header_hash'], data['footer_hash'], addon) return data
def populate(self): self.instance = Addon.objects.create( type=amo.ADDON_PERSONA, status=amo.STATUS_PUBLIC, slug='swag-overload', name='Bands Make Me Dance', description='tha description') self.cat = Category.objects.create(type=amo.ADDON_PERSONA) self.instance.addoncategory_set.create(category=self.cat) self.license = amo.LICENSE_CC_BY.id self.theme = Persona.objects.create( persona_id=0, addon_id=self.instance.id, license=self.license, accentcolor='C0FFEE', textcolor='EFFFFF') Tag(tag_text='sw').save_tag(self.instance) Tag(tag_text='ag').save_tag(self.instance)
def test_public_to_public_already_had_webextension_tag(self): self.file.update(is_webextension=True) Tag(tag_text='firefox57').save_tag(self.addon) assert ( set(self.addon.tags.all().values_list('tag_text', flat=True)) == set(['firefox57'])) self.addon.current_version.update(created=self.days_ago(1)) self.version = version_factory( addon=self.addon, channel=amo.RELEASE_CHANNEL_LISTED, version='3.0.42', file_kw={'status': amo.STATUS_AWAITING_REVIEW}) self.file = self.version.files.all()[0] self.setup_data(amo.STATUS_PUBLIC) # Safeguards. assert isinstance(self.helper.handler, helpers.ReviewFiles) assert self.addon.status == amo.STATUS_PUBLIC assert self.file.status == amo.STATUS_AWAITING_REVIEW assert self.addon.current_version.files.all()[0].status == ( amo.STATUS_PUBLIC) self.helper.handler.process_public() assert ( set(self.addon.tags.all().values_list('tag_text', flat=True)) == set(['firefox57']))
def test_not_blacklisted(self): """Make sure Tag Manager filters right for not blacklisted tags.""" tag1 = Tag(tag_text='abc', blacklisted=False) tag1.save() tag2 = Tag(tag_text='swearword', blacklisted=True) tag2.save() assert Tag.objects.all().count() == 2 assert Tag.objects.not_blacklisted().count() == 1 assert Tag.objects.not_blacklisted()[0] == tag1
def save(self, addon, commit=False): tags_new = self.cleaned_data['tags'] tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AddonFormBasic, self).save(commit=False) addonform.save() return addonform
def add_dynamic_theme_tag(ids, **kw): """Add dynamic theme tag to addons with the specified ids.""" log.info('Adding dynamic theme tag to addons %d-%d [%d].', ids[0], ids[-1], len(ids)) addons = Addon.objects.filter(id__in=ids) for addon in addons: files = addon.current_version.all_files if any('theme' in file_.webext_permissions_list for file_ in files): Tag(tag_text='dynamic theme').save_tag(addon) index_addons.delay([addon.id])
def test_aggregations(self): Tag(tag_text='sky').save_tag(self._addons[0]) Tag(tag_text='sky').save_tag(self._addons[1]) Tag(tag_text='sky').save_tag(self._addons[2]) Tag(tag_text='earth').save_tag(self._addons[0]) Tag(tag_text='earth').save_tag(self._addons[1]) Tag(tag_text='ocean').save_tag(self._addons[0]) self.reindex(Addon) qs = Addon.search().aggregate(tags={'terms': {'field': 'tags'}}) results = list(qs) assert len(results) == 6 assert qs.aggregations == { 'tags': [ { 'doc_count': 3, 'key': 'sky' }, { 'doc_count': 2, 'key': 'earth' }, { 'doc_count': 1, 'key': 'ocean' }, ] }
def add_firefox57_tag(ids, **kw): """Add firefox57 tag to addons with the specified ids.""" log.info('Adding firefox57 tag to addons %d-%d [%d].', ids[0], ids[-1], len(ids)) addons = Addon.objects.filter(id__in=ids) for addon in addons: # This will create a couple extra queries to check for tag/addontag # existence, and then trigger update_tag_stat tasks. But the # alternative is adding activity log manually, making sure we don't # add duplicate tags, manually updating the tag stats, so it's ok for # a one-off task. Tag(tag_text='firefox57').save_tag(addon)
def test_not_denied(self): """Make sure Tag Manager filters right for not denied tags.""" tag1 = Tag(tag_text='abc', denied=False) tag1.save() tag2 = Tag(tag_text='swearword', denied=True) tag2.save() assert Tag.objects.all().count() == 2 assert Tag.objects.not_denied().count() == 1 assert Tag.objects.not_denied()[0] == tag1
def test_not_blacklisted(self): """Make sure Tag Manager filters right for not blacklisted tags.""" tag1 = Tag(tag_text='abc', blacklisted=False) tag1.save() tag2 = Tag(tag_text='swearword', blacklisted=True) tag2.save() eq_(Tag.objects.all().count(), 2) eq_(Tag.objects.not_blacklisted().count(), 1) eq_(Tag.objects.not_blacklisted()[0], tag1)
def save(self, commit=False): data = self.cleaned_data addon = Addon.objects.create(slug=data.get('slug'), status=amo.STATUS_PENDING, type=amo.ADDON_PERSONA) addon.name = {'en-US': data['name']} if data.get('description'): addon.description = data['description'] addon._current_version = Version.objects.create(addon=addon, version='0') addon.save() # Create Persona instance. p = Persona() p.persona_id = 0 p.addon = addon p.header = 'header.png' if data['footer_hash']: p.footer = 'footer.png' if data['accentcolor']: p.accentcolor = data['accentcolor'].lstrip('#') if data['textcolor']: p.textcolor = data['textcolor'].lstrip('#') p.license = data['license'] p.submit = datetime.now() user = self.request.user p.author = user.username p.display_username = user.name p.save() # Save header, footer, and preview images. save_theme.delay(data['header_hash'], data['footer_hash'], addon) # Save user info. addon.addonuser_set.create(user=user, role=amo.AUTHOR_ROLE_OWNER) # Save tags. for t in data['tags']: Tag(tag_text=t).save_tag(addon) # Save categories. AddonCategory(addon=addon, category=data['category']).save() return addon
def process_public(self): """Set an add-on or a version to public.""" # Safeguard to force implementation for unlisted add-ons to completely # override this method. assert self.version.channel == amo.RELEASE_CHANNEL_LISTED # Sign addon. for file_ in self.files: sign_file(file_, settings.SIGNING_SERVER) # Hold onto the status before we change it. status = self.addon.status # Save files first, because set_addon checks to make sure there # is at least one public file or it won't make the addon public. self.set_files(amo.STATUS_PUBLIC, self.files) if self.set_addon_status: self.set_addon(status=amo.STATUS_PUBLIC) # If we've approved a webextension, add a tag identifying them as such. if any(file_.is_webextension for file_ in self.files): Tag(tag_text='firefox57').save_tag(self.addon) # Increment approvals counter. AddonApprovalsCounter.increment_for_addon(addon=self.addon) self.log_action(amo.LOG.APPROVE_VERSION) template = u'%s_to_public' % self.review_type subject = u'Mozilla Add-ons: %s %s Approved' self.notify_email(template, subject) self.log_public_message() log.info(u'Sending email for %s' % (self.addon)) # Assign reviewer incentive scores. if self.request: ReviewerScore.award_points(self.request.user, self.addon, status, version=self.version)
def test_tag_filters_on_search_page(self): Tag(tag_text='sky').save_tag(self.addons[0]) Tag(tag_text='sky').save_tag(self.addons[1]) Tag(tag_text='sky').save_tag(self.addons[2]) Tag(tag_text='earth').save_tag(self.addons[0]) Tag(tag_text='earth').save_tag(self.addons[1]) Tag(tag_text='ocean').save_tag(self.addons[0]) self.reindex(Addon) response = self.client.get(self.url, {'tag': 'sky'}) assert response.status_code == 200 assert self.get_results(response) # Tags filter UI should show 4 items ("All Tags" + 3 different tags) tags_links = pq(response.content)('#tag-facets li a[data-params]') assert len(tags_links) == 4 # First link should be "All Tags". assert tags_links[0].attrib['href'] == self.url assert json.loads(tags_links[0].attrib['data-params']) == { 'tag': None, 'page': None } # Then we should have the tags. expected_tags = ('sky', 'earth', 'ocean') for index, link in enumerate(tags_links[1:]): tag_text = expected_tags[index] assert link.attrib['href'] == urlparams(self.url, tag=tag_text) assert json.loads(link.attrib['data-params']) == { 'tag': tag_text, 'page': None } # Selected tag should be the one we passed in the URL: 'sky'. link = pq(response.content)('#tag-facets li.selected a[data-params]') assert json.loads(link.attr('data-params')) == { 'tag': 'sky', 'page': None }
def addon_factory(status=amo.STATUS_PUBLIC, version_kw=None, file_kw=None, **kw): version_kw = version_kw or {} # Disconnect signals until the last save. post_save.disconnect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') type_ = kw.pop('type', amo.ADDON_EXTENSION) popularity = kw.pop('popularity', None) persona_id = kw.pop('persona_id', None) tags = kw.pop('tags', []) users = kw.pop('users', []) when = _get_created(kw.pop('created', None)) category = kw.pop('category', None) default_locale = kw.get('default_locale', settings.LANGUAGE_CODE) # Keep as much unique data as possible in the uuid: '-' aren't important. name = kw.pop('name', u'Addôn %s' % six.text_type(uuid.uuid4()).replace('-', '')) slug = kw.pop('slug', None) if slug is None: slug = name.replace(' ', '-').lower()[:30] kwargs = { # Set artificially the status to STATUS_PUBLIC for now, the real # status will be set a few lines below, after the update_version() # call. This prevents issues when calling addon_factory with # STATUS_DELETED. 'status': amo.STATUS_PUBLIC, 'default_locale': default_locale, 'name': name, 'slug': slug, 'average_daily_users': popularity or random.randint(200, 2000), 'weekly_downloads': popularity or random.randint(200, 2000), 'created': when, 'last_updated': when, } if type_ != amo.ADDON_PERSONA and 'summary' not in kw: # Assign a dummy summary if none was specified in keyword args, unless # we're creating a Persona since they don't have summaries. kwargs['summary'] = u'Summary for %s' % name if type_ not in [amo.ADDON_PERSONA, amo.ADDON_SEARCH]: # Personas and search engines don't need guids kwargs['guid'] = kw.pop('guid', '{%s}' % six.text_type(uuid.uuid4())) kwargs.update(kw) # Save 1. with translation.override(default_locale): addon = Addon.objects.create(type=type_, **kwargs) # Save 2. version = version_factory(file_kw, addon=addon, **version_kw) if addon.type == amo.ADDON_PERSONA: addon._current_version = version persona_id = persona_id if persona_id is not None else addon.id # Save 3. Persona.objects.create(addon=addon, popularity=addon.average_daily_users, persona_id=persona_id) addon.update_version() addon.status = status for tag in tags: Tag(tag_text=tag).save_tag(addon) for user in users: addon.addonuser_set.create(user=user) application = version_kw.get('application', amo.FIREFOX.id) if not category: static_category = random.choice( list(CATEGORIES[application][addon.type].values())) category = Category.from_static_category(static_category, True) AddonCategory.objects.create(addon=addon, category=category) # Put signals back. post_save.connect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') # Save 4. addon.save() if addon.type == amo.ADDON_PERSONA: # Personas only have one version and signals.version_changed is never # fired for them - instead it gets updated through a cron (!). We do # need to get it right in some tests like the ui tests, so we call the # task ourselves. version_changed(addon.pk) # Potentially update is_public on authors [user.update_is_public() for user in users] if 'nomination' in version_kw: # If a nomination date was set on the version, then it might have been # erased at post_save by addons.models.watch_status() version.save() return addon
def addon_factory(status=amo.STATUS_PUBLIC, version_kw=None, file_kw=None, **kw): version_kw = version_kw or {} # Disconnect signals until the last save. post_save.disconnect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') type_ = kw.pop('type', amo.ADDON_EXTENSION) popularity = kw.pop('popularity', None) persona_id = kw.pop('persona_id', None) tags = kw.pop('tags', []) users = kw.pop('users', []) when = _get_created(kw.pop('created', None)) # Keep as much unique data as possible in the uuid: '-' aren't important. name = kw.pop('name', u'Addôn %s' % unicode(uuid.uuid4()).replace('-', '')) kwargs = { # Set artificially the status to STATUS_PUBLIC for now, the real # status will be set a few lines below, after the update_version() # call. This prevents issues when calling addon_factory with # STATUS_DELETED. 'status': amo.STATUS_PUBLIC, 'name': name, 'slug': name.replace(' ', '-').lower()[:30], 'average_daily_users': popularity or random.randint(200, 2000), 'weekly_downloads': popularity or random.randint(200, 2000), 'created': when, 'last_updated': when, } if 'is_listed' not in kw and 'channel' in version_kw: kw['is_listed'] = version_kw['channel'] == amo.RELEASE_CHANNEL_LISTED kwargs.update(kw) # Save 1. if type_ == amo.ADDON_PERSONA: # Personas need to start life as an extension for versioning. addon = Addon.objects.create(type=amo.ADDON_EXTENSION, **kwargs) else: addon = Addon.objects.create(type=type_, **kwargs) # Save 2. if 'channel' not in version_kw and 'is_listed' in kw: version_kw['channel'] = (amo.RELEASE_CHANNEL_LISTED if kw['is_listed'] else amo.RELEASE_CHANNEL_UNLISTED) version = version_factory(file_kw, addon=addon, **version_kw) addon.update_version() addon.status = status if type_ == amo.ADDON_PERSONA: addon.type = type_ persona_id = persona_id if persona_id is not None else addon.id # Save 3. Persona.objects.create(addon=addon, popularity=addon.weekly_downloads, persona_id=persona_id) for tag in tags: Tag(tag_text=tag).save_tag(addon) for user in users: addon.addonuser_set.create(user=user) # Put signals back. post_save.connect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') # Save 4. addon.save() if 'nomination' in version_kw: # If a nomination date was set on the version, then it might have been # erased at post_save by addons.models.watch_status() version.save() return addon
def from_upload(cls, upload, version, platform, is_beta=False, parse_data={}): addon = version.addon file_ = cls(version=version, platform=platform) upload.path = smart_path(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] if file_.jetpack_version: Tag(tag_text='jetpack').save_tag(addon) file_.no_restart = parse_data.get('no_restart', False) file_.strict_compatibility = parse_data.get('strict_compatibility', False) file_.is_multi_package = parse_data.get('is_multi_package', False) file_.is_experiment = parse_data.get('is_experiment', False) file_.is_webextension = parse_data.get('is_webextension', False) if is_beta and addon.status == amo.STATUS_PUBLIC: file_.status = amo.STATUS_BETA elif addon.trusted: # New files in trusted add-ons automatically receive the correct # approved status for their review class. if addon.status == amo.STATUS_PUBLIC: file_.status = amo.STATUS_PUBLIC elif addon.status in amo.LITE_STATUSES: file_.status = amo.STATUS_LITE file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. destinations = [version.path_prefix] if file_.status in amo.MIRROR_STATUSES: destinations.append(version.mirror_path_prefix) for dest in destinations: copy_stored_file(upload.path, os.path.join(dest, nfd_str(file_.filename))) if upload.validation: # Import loop. from olympia.devhub.tasks import annotate_validation_results from olympia.devhub.utils import ValidationAnnotator validation = annotate_validation_results(validation) FileValidation.from_json(file_, validation) # Copy annotations from any previously approved file. ValidationAnnotator(file_).update_annotations() return file_
def addon_factory(status=amo.STATUS_APPROVED, version_kw=None, file_kw=None, **kw): version_kw = version_kw or {} # Disconnect signals until the last save. post_save.disconnect( addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index' ) post_save.disconnect( update_es_for_promoted, sender=PromotedAddon, dispatch_uid='addons.search.index' ) post_save.disconnect( update_es_for_promoted_approval, sender=PromotedApproval, dispatch_uid='addons.search.index', ) type_ = kw.pop('type', amo.ADDON_EXTENSION) popularity = kw.pop('popularity', None) tags = kw.pop('tags', []) users = kw.pop('users', []) when = _get_created(kw.pop('created', None)) category = kw.pop('category', None) default_locale = kw.get('default_locale', settings.LANGUAGE_CODE) # Keep as much unique data as possible in the uuid: '-' aren't important. name = kw.pop('name', 'Addôn %s' % str(uuid.uuid4()).replace('-', '')) slug = kw.pop('slug', None) if slug is None: slug = name.replace(' ', '-').lower()[:30] promoted_group = kw.pop('promoted', None) kwargs = { # Set artificially the status to STATUS_APPROVED for now, the real # status will be set a few lines below, after the update_version() # call. This prevents issues when calling addon_factory with # STATUS_DELETED. 'status': amo.STATUS_APPROVED, 'default_locale': default_locale, 'name': name, 'slug': slug, 'average_daily_users': popularity or random.randint(200, 2000), 'weekly_downloads': popularity or random.randint(200, 2000), 'created': when, 'last_updated': when, } if 'summary' not in kw: # Assign a dummy summary if none was specified in keyword args. kwargs['summary'] = 'Summary for %s' % name kwargs['guid'] = kw.pop('guid', '{%s}' % str(uuid.uuid4())) kwargs.update(kw) # Save 1. with translation.override(default_locale): addon = Addon.objects.create(type=type_, **kwargs) # Save 2. if promoted_group: PromotedAddon.objects.create(addon=addon, group_id=promoted_group.id) if 'promotion_approved' not in version_kw: version_kw['promotion_approved'] = True version = version_factory(file_kw, addon=addon, **version_kw) addon.update_version() # version_changed task will be triggered and will update last_updated in # database for this add-on depending on the state of the version / files. # We're calling the function it uses to compute the value ourselves and= # sticking that into the attribute ourselves so that we already have the # correct value in the instance we are going to return. # Note: the aim is to have the instance consistent with what will be in the # database because of the task, *not* to be consistent with the status of # the add-on. Because we force the add-on status without forcing the status # of the latest file, the value we end up with might not make sense in some # cases. addon.last_updated = compute_last_updated(addon) addon.status = status for tag in tags: Tag(tag_text=tag).save_tag(addon) for user in users: addon.addonuser_set.create(user=user) application = version_kw.get('application', amo.FIREFOX.id) if not category and addon.type in CATEGORIES[application]: category = random.choice(list(CATEGORIES[application][addon.type].values())) if category: AddonCategory.objects.create(addon=addon, category=category) # Put signals back. post_save.connect( addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index' ) post_save.connect( update_es_for_promoted, sender=PromotedAddon, dispatch_uid='addons.search.index' ) post_save.connect( update_es_for_promoted_approval, sender=PromotedApproval, dispatch_uid='addons.search.index', ) # Save 4. addon.save() if addon.guid: AddonGUID.objects.create(addon=addon, guid=addon.guid) # Potentially update is_public on authors [user.update_is_public() for user in users] if 'nomination' in version_kw: # If a nomination date was set on the version, then it might have been # erased at post_save by addons.models.watch_status() version.save() return addon
def addon_factory(status=amo.STATUS_PUBLIC, version_kw=None, file_kw=None, **kw): version_kw = version_kw or {} # Disconnect signals until the last save. post_save.disconnect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') type_ = kw.pop('type', amo.ADDON_EXTENSION) popularity = kw.pop('popularity', None) persona_id = kw.pop('persona_id', None) tags = kw.pop('tags', []) users = kw.pop('users', []) when = _get_created(kw.pop('created', None)) category = kw.pop('category', None) # Keep as much unique data as possible in the uuid: '-' aren't important. name = kw.pop('name', u'Addôn %s' % unicode(uuid.uuid4()).replace('-', '')) kwargs = { # Set artificially the status to STATUS_PUBLIC for now, the real # status will be set a few lines below, after the update_version() # call. This prevents issues when calling addon_factory with # STATUS_DELETED. 'status': amo.STATUS_PUBLIC, 'name': name, 'slug': name.replace(' ', '-').lower()[:30], 'average_daily_users': popularity or random.randint(200, 2000), 'weekly_downloads': popularity or random.randint(200, 2000), 'created': when, 'last_updated': when, } if type_ != amo.ADDON_PERSONA: # Personas don't have a summary. kwargs['summary'] = u'Summary for %s' % name kwargs.update(kw) # Save 1. if type_ == amo.ADDON_PERSONA: # Personas need to start life as an extension for versioning. addon = Addon.objects.create(type=amo.ADDON_EXTENSION, **kwargs) else: addon = Addon.objects.create(type=type_, **kwargs) # Save 2. version = version_factory(file_kw, addon=addon, **version_kw) addon.update_version() addon.status = status if type_ == amo.ADDON_PERSONA: addon.type = type_ persona_id = persona_id if persona_id is not None else addon.id # Save 3. Persona.objects.create(addon=addon, popularity=addon.weekly_downloads, persona_id=persona_id) for tag in tags: Tag(tag_text=tag).save_tag(addon) for user in users: addon.addonuser_set.create(user=user) application = version_kw.get('application', amo.FIREFOX.id) if not category: static_category = random.choice( CATEGORIES[application][type_].values()) category, _ = Category.objects.get_or_create( id=static_category.id, defaults=static_category.__dict__) AddonCategory.objects.create(addon=addon, category=category) # Put signals back. post_save.connect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') # Save 4. addon.save() if 'nomination' in version_kw: # If a nomination date was set on the version, then it might have been # erased at post_save by addons.models.watch_status() version.save() return addon
def addon_factory(status=amo.STATUS_APPROVED, version_kw=None, file_kw=None, **kw): version_kw = version_kw or {} # Disconnect signals until the last save. post_save.disconnect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') type_ = kw.pop('type', amo.ADDON_EXTENSION) popularity = kw.pop('popularity', None) tags = kw.pop('tags', []) users = kw.pop('users', []) when = _get_created(kw.pop('created', None)) category = kw.pop('category', None) default_locale = kw.get('default_locale', settings.LANGUAGE_CODE) # Keep as much unique data as possible in the uuid: '-' aren't important. name = kw.pop('name', u'Addôn %s' % str(uuid.uuid4()).replace('-', '')) slug = kw.pop('slug', None) if slug is None: slug = name.replace(' ', '-').lower()[:30] should_be_recommended = kw.pop('recommended', False) kwargs = { # Set artificially the status to STATUS_APPROVED for now, the real # status will be set a few lines below, after the update_version() # call. This prevents issues when calling addon_factory with # STATUS_DELETED. 'status': amo.STATUS_APPROVED, 'default_locale': default_locale, 'name': name, 'slug': slug, 'average_daily_users': popularity or random.randint(200, 2000), 'weekly_downloads': popularity or random.randint(200, 2000), 'created': when, 'last_updated': when, } if 'summary' not in kw: # Assign a dummy summary if none was specified in keyword args. kwargs['summary'] = u'Summary for %s' % name if type_ not in [amo.ADDON_SEARCH]: # Search engines don't need guids kwargs['guid'] = kw.pop('guid', '{%s}' % str(uuid.uuid4())) kwargs.update(kw) # Save 1. with translation.override(default_locale): addon = Addon.objects.create(type=type_, **kwargs) # Save 2. if should_be_recommended: version_kw['recommendation_approved'] = True version = version_factory(file_kw, addon=addon, **version_kw) addon.update_version() addon.status = status for tag in tags: Tag(tag_text=tag).save_tag(addon) for user in users: addon.addonuser_set.create(user=user) application = version_kw.get('application', amo.FIREFOX.id) if not category: static_category = random.choice( list(CATEGORIES[application][addon.type].values())) category = Category.from_static_category(static_category, True) AddonCategory.objects.create(addon=addon, category=category) if should_be_recommended: DiscoveryItem.objects.create(addon=addon, recommendable=True) # Put signals back. post_save.connect(addon_update_search_index, sender=Addon, dispatch_uid='addons.search.index') # Save 4. addon.save() if addon.guid: AddonGUID.objects.create(addon=addon, guid=addon.guid) # Potentially update is_public on authors [user.update_is_public() for user in users] if 'nomination' in version_kw: # If a nomination date was set on the version, then it might have been # erased at post_save by addons.models.watch_status() version.save() return addon
def add_dynamic_theme_tag(version): if version.channel != amo.RELEASE_CHANNEL_LISTED: return files = version.all_files if any('theme' in file_.permissions for file_ in files): Tag(tag_text='dynamic theme').save_tag(version.addon)