Beispiel #1
0
    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)
Beispiel #2
0
    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
Beispiel #3
0
 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
Beispiel #6
0
    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
Beispiel #7
0
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])
Beispiel #8
0
    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'
                },
            ]
        }
Beispiel #9
0
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)
Beispiel #10
0
    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)
Beispiel #12
0
    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
Beispiel #13
0
    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)
Beispiel #14
0
    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
Beispiel #16
0
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
Beispiel #17
0
    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_
Beispiel #18
0
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
Beispiel #19
0
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
Beispiel #20
0
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
Beispiel #21
0
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)