Ejemplo n.º 1
0
def geoip_suggestion(request):
    """
    Ajax view to return the localized text for GeoIP locale change suggestion.

    Takes one parameter from the querystring:

        * locales - a form encoded list of locales to translate to.

    Example url: /localize?locales[]=es&locales[]=en-US
    """
    locales = request.GET.getlist('locales[]')

    response = {'locales': {}}
    for locale in locales:
        # English and native names for the language
        response['locales'][locale] = LOCALES[locale]
        with uselocale(locale):
            # This is using our JS-style string formatting.
            response[locale] = {
                'suggestion': _('Would you like to view this page in '
                                '%(language)s instead?'),
                'confirm': _('Yes'),
                'cancel': _('No'),
            }

    return HttpResponse(json.dumps(response), content_type='application/json')
Ejemplo n.º 2
0
def hide_tweet(request):
    """
    Hide the tweet with a given ID. Only hides tweets that are not replies
    and do not have replies.

    Returns proper HTTP status codes.
    """
    # If feature disabled, bail.
    if not settings.CC_ALLOW_REMOVE:
        return HttpResponse(status=418)  # I'm a teapot.

    try:
        id = int(request.POST.get('id'))
    except (ValueError, TypeError):
        return HttpResponseBadRequest(_('Invalid ID.'))

    try:
        tweet = Tweet.objects.get(pk=id)
    except Tweet.DoesNotExist:
        return HttpResponseNotFound(_('Invalid ID.'))

    if (tweet.reply_to is not None or
            Tweet.objects.filter(reply_to=tweet).exists()):
        return HttpResponseBadRequest(_('Tweets that are replies or have '
                                        'replies must not be hidden.'))

    try:
        tweet.hidden = True
        tweet.save(force_update=True)
    except Exception, e:
        return HttpResponseServerError(
            _('An error occured: {message}').format(message=e))
Ejemplo n.º 3
0
def ProfileForm(*args, **kw):
    # If the add-on takes contributions, then both fields are required.
    addon = kw['instance']
    fields_required = (kw.pop('required', False) or
                       bool(addon.takes_contributions))
    if addon.is_webapp():
        the_reason_label = _('Why did you make this app?')
        the_future_label = _("What's next for this app?")
    else:
        the_reason_label = _('Why did you make this add-on?')
        the_future_label = _("What's next for this add-on?")

    class _Form(TranslationFormMixin, happyforms.ModelForm):
        the_reason = TransField(widget=TransTextarea(),
                                     required=fields_required,
                                     label=the_reason_label)
        the_future = TransField(widget=TransTextarea(),
                                     required=fields_required,
                                     label=the_future_label)

        class Meta:
            model = Addon
            fields = ('the_reason', 'the_future')

    return _Form(*args, **kw)
Ejemplo n.º 4
0
    def form_valid(self, form):
        """Custom form validation to support email changing.

        If user is already authenticated and reaches this points, it's
        an email changing procedure. Validate that email is good and
        save it in the database.

        Otherwise continue with the default django-browserid verification.
        """
        if not self.request.user.is_authenticated():
            return super(BrowserIDVerify, self).form_valid(form)

        failure_url = urlparams(reverse('phonebook:profile_edit'), bid_login_failed=1)
        self.assertion = form.cleaned_data['assertion']
        self.audience = get_audience(self.request)
        result = verify(self.assertion, self.audience)
        if not result:
            messages.error(self.request, _('Authentication failed.'))
            return redirect(failure_url)

        email = result['email']

        if User.objects.filter(email=email).exists():
            messages.error(self.request, _('Email already exists in the database.'))
            return redirect('phonebook:logout')

        user = self.request.user
        user.email = email
        user.save()
        return redirect('phonebook:profile_view', user.username)
Ejemplo n.º 5
0
def twitter_post(request):
    """Post a tweet, and return a rendering of it (and any replies)."""

    try:
        reply_to_id = int(request.POST.get('reply_to', ''))
    except ValueError:
        # L10n: the tweet needs to be a reply to another tweet.
        return HttpResponseBadRequest(_('Reply-to is empty'))

    content = request.POST.get('content', '')
    if len(content) == 0:
        # L10n: the tweet has no content.
        return HttpResponseBadRequest(_('Message is empty'))

    if len(content) > 140:
        return HttpResponseBadRequest(_('Message is too long'))

    try:
        credentials = request.twitter.api.verify_credentials()
        username = credentials['screen_name']
        if username in settings.CC_BANNED_USERS:
            return render(request, 'customercare/tweets.html',
                          {'tweets': []})
        result = request.twitter.api.update_status(
            status=content,
            in_reply_to_status_id=reply_to_id)
    except (TwythonError, TwythonAuthError), e:
        # L10n: {message} is an error coming from our twitter api library
        return HttpResponseBadRequest(
            _('An error occured: {message}').format(message=e))
Ejemplo n.º 6
0
    def file_details(self, file):
        platform = file.platform_id
        if self.latest and (
            self.addon.status == file.status == amo.STATUS_PUBLIC):
            url = file.latest_xpi_url()
        else:
            url = file.get_url_path(self.src)

        if platform == amo.PLATFORM_ALL.id:
            text, os = _('Download Now'), None
        else:
            text, os = _('Download'), amo.PLATFORMS[platform]

        if self.show_eula:
            # L10n: please keep   in the string so → does not wrap.
            text = jinja2.Markup(_('Continue to Download →'))
            url = file.eula_url()
        elif self.accept_eula:
            text = _('Accept and Download')
        elif self.show_contrib:
            # The eula doesn't exist or has been hit already.
            # L10n: please keep   in the string so → does not wrap.
            text = jinja2.Markup(_('Continue to Download →'))
            roadblock = reverse('addons.roadblock', args=[self.addon.id])
            url = urlparams(roadblock, eula='', version=self.version.version)

        return text, url, os
Ejemplo n.º 7
0
def in_app_config(request, addon_id, addon, webapp=True):
    inapp = addon.premium_type in amo.ADDON_INAPPS
    if not inapp:
        messages.error(request,
                       _('Your app is not configured for in-app payments.'))
        return redirect(reverse('mkt.developers.apps.payments',
                                args=[addon.app_slug]))
    try:
        account = addon.app_payment_account
    except ObjectDoesNotExist:
        messages.error(request, _('No payment account for this app.'))
        return redirect(reverse('mkt.developers.apps.payments',
                                args=[addon.app_slug]))

    seller_config = get_seller_product(account)

    owner = acl.check_addon_ownership(request, addon)
    if request.method == 'POST':
        # Reset the in-app secret for the app.
        (client.api.generic
               .product(seller_config['resource_pk'])
               .patch(data={'secret': generate_key(48)}))
        messages.success(request, _('Changes successfully saved.'))
        return redirect(reverse('mkt.developers.apps.in_app_config',
                                args=[addon.app_slug]))

    return jingo.render(request, 'developers/payments/in-app-config.html',
                        {'addon': addon, 'owner': owner,
                         'seller_config': seller_config})
Ejemplo n.º 8
0
def ajax(request):
    """Query for a user matching a given email."""

    if 'q' not in request.GET:
        raise http.Http404()

    data = {'status': 0, 'message': ''}

    email = request.GET.get('q', '').strip()
    dev_only = request.GET.get('dev', '1')
    try:
        dev_only = int(dev_only)
    except ValueError:
        dev_only = 1
    dev_only = dev_only and settings.MARKETPLACE

    if not email:
        data.update(message=_('An email address is required.'))
        return data

    user = UserProfile.objects.filter(email=email)
    if dev_only:
        user = user.exclude(read_dev_agreement=None)

    msg = _('A user with that email address does not exist.')
    msg_dev = _('A user with that email address does not exist, or the user '
                'has not yet accepted the developer agreement.')

    if user:
        data.update(status=1, id=user[0].id, name=user[0].name)
    else:
        data['message'] = msg_dev if dev_only else msg

    return escape_all(data)
Ejemplo n.º 9
0
def setup_viewer(request, file_obj):
    data = {
        "file": file_obj,
        "version": file_obj.version,
        "addon": file_obj.version.addon,
        "status": False,
        "selected": {},
        "validate_url": "",
    }

    if acl.check_reviewer(request) or acl.check_addon_ownership(
        request, file_obj.version.addon, viewer=True, ignore_disabled=True
    ):
        data["validate_url"] = reverse(
            "mkt.developers.apps.json_file_validation", args=[file_obj.version.addon.app_slug, file_obj.id]
        )

    if acl.check_reviewer(request):
        data["file_link"] = {
            "text": _("Back to review"),
            "url": reverse("reviewers.apps.review", args=[data["addon"].app_slug]),
        }
    else:
        data["file_link"] = {"text": _("Back to app"), "url": reverse("detail", args=[data["addon"].pk])}
    return data
Ejemplo n.º 10
0
        def _make_mail(locale, user, context):
            # Avoid circular import issues
            from kitsune.users.helpers import display_name

            is_asker = asker_id == user.id
            if is_asker:
                subject = _(
                    u'%s posted an answer to your question "%s"'
                    % (display_name(self.answer.creator), self.instance.title)
                )
                text_template = "questions/email/new_answer_to_asker.ltxt"
                html_template = "questions/email/new_answer_to_asker.html"
            else:
                subject = _(u"Re: %s" % self.instance.title)
                text_template = "questions/email/new_answer.ltxt"
                html_template = "questions/email/new_answer.html"

            mail = email_utils.make_mail(
                subject=subject,
                text_template=text_template,
                html_template=html_template,
                context_vars=context,
                from_email="Mozilla Support Forum <*****@*****.**>",
                to_email=user.email,
            )

            return mail
Ejemplo n.º 11
0
def emailchange(request, user_id, token, hash):
    user = get_object_or_404(UserProfile, id=user_id)

    try:
        _uid, newemail = EmailResetCode.parse(token, hash)
    except ValueError:
        return http.HttpResponse(status=400)

    if _uid != user.id:
        # I'm calling this a warning because invalid hashes up to this point
        # could be any number of things, but this is a targeted attack from
        # one user account to another
        log.warning((u"[Tampering] Valid email reset code for UID (%s) "
                     "attempted to change email address for user (%s)")
                                                        % (_uid, user))
        return http.HttpResponse(status=400)

    user.email = newemail
    user.save()

    l = {'user': user, 'newemail': newemail}
    log.info(u"User (%(user)s) confirmed new email address (%(newemail)s)" % l)
    messages.success(request, _('Your email address was changed successfully'),
            _(u'From now on, please use {0} to log in.').format(newemail))

    return http.HttpResponseRedirect(reverse('users.edit'))
Ejemplo n.º 12
0
def parse_xpi(xpi, addon=None, check=True):
    """Extract and parse an XPI."""
    # Extract to /tmp
    path = tempfile.mkdtemp()
    try:
        xpi = get_file(xpi)
        extract_xpi(xpi, path)
        xpi_info = Extractor.parse(path)
    except forms.ValidationError:
        raise
    except IOError as e:
        if len(e.args) < 2:
            errno, strerror = None, e[0]
        else:
            errno, strerror = e
        log.error('I/O error({0}): {1}'.format(errno, strerror))
        raise forms.ValidationError(_('Could not parse install.rdf.'))
    except Exception:
        log.error('XPI parse error', exc_info=True)
        raise forms.ValidationError(_('Could not parse install.rdf.'))
    finally:
        rm_local_tmp_dir(path)

    if check:
        return check_xpi_info(xpi_info, addon)
    else:
        return xpi_info
Ejemplo n.º 13
0
def api(request):
    try:
        access = Access.objects.get(user=request.user)
    except Access.DoesNotExist:
        access = None

    roles = request.amo_user.groups.all()
    if roles:
        messages.error(request, _('Users with roles cannot use the API.'))

    elif not request.amo_user.read_dev_agreement:
        messages.error(request, _('You must accept the terms of service.'))

    elif request.method == 'POST':
        if 'delete' in request.POST:
            if access:
                access.delete()
                messages.success(request, _('API key deleted.'))

        else:
            if not access:
                key = 'mkt:%s:%s' % (request.amo_user.pk,
                                     request.amo_user.email)
                access = Access.objects.create(key=key, user=request.user,
                                               secret=generate())
            else:
                access.update(secret=generate())
            messages.success(request, _('New API key generated.'))

        return redirect(reverse('mkt.developers.apps.api'))

    return jingo.render(request, 'developers/api.html',
                        {'consumer': access, 'profile': profile,
                         'roles': roles})
Ejemplo n.º 14
0
    def clean_price(self):
        price_value = self.cleaned_data.get('price')
        premium_type = self.cleaned_data.get('premium_type')
        if ((premium_type in amo.ADDON_PREMIUMS
                or premium_type == amo.ADDON_FREE_INAPP)
                and not price_value and not self.is_toggling()):
            raise_required()

        if not price_value and self.fields['price'].required is False:
            return None

        # Special case for a free app - in-app payments must be enabled.
        # Note: this isn't enforced for tier zero apps.
        if price_value == 'free':
            if self.cleaned_data.get('allow_inapp') != 'True':
                raise ValidationError(_('If app is Free, '
                                        'in-app payments must be enabled'))
            return price_value

        try:
            price = Price.objects.get(pk=price_value, active=True)
        except (ValueError, Price.DoesNotExist):
            raise ValidationError(_('Not a valid choice'))

        return price
Ejemplo n.º 15
0
def answer_vote(request, question_id, answer_id):
    """Vote for Helpful/Not Helpful answers"""
    answer = get_object_or_404(Answer, pk=answer_id, question=question_id)
    if answer.question.is_locked:
        raise PermissionDenied

    if not answer.has_voted(request):
        vote = AnswerVote(answer=answer)

        if 'helpful' in request.REQUEST:
            vote.helpful = True
            AnswerMarkedHelpfulAction(answer.creator).save()
            message = _('Glad to hear it!')
        else:
            AnswerMarkedNotHelpfulAction(answer.creator).save()
            message = _('Sorry to hear that.')

        if request.user.is_authenticated():
            vote.creator = request.user
        else:
            vote.anonymous_id = request.anonymous.anonymous_id

        vote.save()
        ua = request.META.get('HTTP_USER_AGENT')
        if ua:
            vote.add_metadata('ua', ua[:1000])  # 1000 max_length
        statsd.incr('questions.votes.answer')
    else:
        message = _('You already voted on this reply.')

    if request.is_ajax():
        return HttpResponse(json.dumps({'message': message}))

    return HttpResponseRedirect(answer.get_absolute_url())
Ejemplo n.º 16
0
def join_group(request, group_pk):
    """User request to join group."""
    group = get_object_or_404(Group, pk=group_pk)
    profile_to_add = request.user.userprofile

    # TODO: this duplicates some of the logic in Group.user_can_join(), but we
    # want to give the user a message that's specific to the reason they can't join.
    # Can we make this DRYer?

    if group.has_member(profile_to_add):
        messages.error(request, _('You are already in this group.'))
    elif group.has_pending_member(profile_to_add):
        messages.error(request, _('Your request to join this group is still pending.'))
    elif group.accepting_new_members == 'no':
        messages.error(request, _('This group is not accepting requests to join.'))
    else:
        if group.accepting_new_members == 'yes':
            group.add_member(profile_to_add)
            messages.info(request, _('You have been added to this group.'))
        elif group.accepting_new_members == 'by_request':
            group.add_member(profile_to_add, status=GroupMembership.PENDING)
            messages.info(request,
                          _('Your membership request is pending approval by the group curator.'))

    return redirect(reverse('groups:show_group', args=[group.url]))
Ejemplo n.º 17
0
def ajax(request):
    """Query for a user matching a given email."""

    if "q" not in request.GET:
        raise http.Http404()

    data = {"status": 0, "message": ""}

    email = request.GET.get("q", "").strip()
    dev_only = request.GET.get("dev", "1")
    try:
        dev_only = int(dev_only)
    except ValueError:
        dev_only = 1
    dev_only = dev_only and settings.MARKETPLACE

    if not email:
        data.update(message=_("An email address is required."))
        return data

    user = UserProfile.objects.filter(email=email)
    if dev_only:
        user = user.exclude(read_dev_agreement=None)

    msg = _("A user with that email address does not exist.")
    msg_dev = _(
        "A user with that email address does not exist, or the user " "has not yet accepted the developer agreement."
    )

    if user:
        data.update(status=1, id=user[0].id, name=user[0].name)
    else:
        data["message"] = msg_dev if dev_only else msg

    return escape_all(data)
Ejemplo n.º 18
0
def _transaction_summary(tx_uuid):
    """Get transaction details from Solitude API."""
    contrib = get_object_or_404(Contribution, uuid=tx_uuid)
    refund_contribs = contrib.get_refund_contribs()
    refund_contrib = refund_contribs[0] if refund_contribs.exists() else None

    # Get refund status.
    refund_status = None
    if refund_contrib and refund_contrib.refund.status == amo.REFUND_PENDING:
        try:
            refund_status = REFUND_STATUSES[
                client.api.bango.refund.status.get(data={"uuid": refund_contrib.transaction_id})["status"]
            ]
        except HttpServerError:
            refund_status = _("Currently unable to retrieve refund status.")

    return {
        # Solitude data.
        "refund_status": refund_status,
        # Zamboni data.
        "app": contrib.addon,
        "contrib": contrib,
        "related": contrib.related,
        "type": amo.CONTRIB_TYPES.get(contrib.type, _("Incomplete")),
        # Whitelist what is refundable.
        "is_refundable": ((contrib.type == amo.CONTRIB_PURCHASE) and not refund_contrib),
    }
Ejemplo n.º 19
0
def reply(request, addon, review_id):
    is_admin = acl.action_allowed(request, 'Addons', 'Edit')
    is_author = acl.check_addon_ownership(request, addon, dev=True)
    if not (is_admin or is_author):
        raise PermissionDenied

    review = get_object_or_404(Review.objects, pk=review_id, addon=addon)
    form = ReviewReplyForm(request.POST or None)
    if form.is_valid():
        d = dict(reply_to=review, addon=addon,
                 defaults=dict(user=request.amo_user))
        reply, new = Review.objects.get_or_create(**d)
        for k, v in _review_details(request, addon, form).items():
            setattr(reply, k, v)
        reply.save()
        action = 'New' if new else 'Edited'
        if new:
            amo.log(amo.LOG.ADD_REVIEW, addon, reply)
        else:
            amo.log(amo.LOG.EDIT_REVIEW, addon, reply)

        log.debug('%s reply to %s: %s' % (action, review_id, reply.id))
        messages.success(request,
                         _('Your reply was successfully added.') if new else
                         _('Your reply was successfully updated.'))

    return http.HttpResponse()
Ejemplo n.º 20
0
def account_settings(request):
    ctx = {}

    # Don't use `request.amo_user` because it's too cached.
    user = request.user
    if user.is_authenticated():
        amo_user = user.get_profile()
        form = forms.UserEditForm(request.POST or None, instance=amo_user)
        if request.method == 'POST':
            if form.is_valid():
                form.save()
                messages.success(request, _('Settings Updated.'))
                amo.log(amo.LOG.USER_EDITED)
                response = redirect('account.settings')
                # TODO: Detect when we're changing the user's locale and region
                # and bust on '/', bust on '/settings' for everything else.
                bust_fragments(response, '/')
                return response
            else:
                messages.form_errors(request)
        ctx = {'form': form, 'amouser': amo_user}
    else:
        if request.method == 'POST':
            messages.success(request, _('Settings Updated.'))

    return jingo.render(request, 'account/settings.html', ctx)
Ejemplo n.º 21
0
def reviewers_breadcrumbs(context, queue=None, items=None):
    """
    Wrapper function for ``breadcrumbs``. Prepends 'Editor Tools'
    breadcrumbs.

    **queue**
        Explicit queue type to set.
    **items**
        list of [(url, label)] to be inserted after Add-on.
    """
    crumbs = [(reverse('reviewers.home'), _('Reviewer Tools'))]

    if queue:
        queues = {'pending': _('Apps'),
                  'rereview': _('Re-reviews'),
                  'updates': _('Updates'),
                  'escalated': _('Escalations'),
                  'device': _('Device'),
                  'moderated': _('Moderated Reviews'),
                  'abuse': _('Abuse Reports'),
                  'reviewing': _('Reviewing'),

                  'region': _('Regional Queues')}

        if items:
            url = reverse('reviewers.apps.queue_%s' % queue)
        else:
            # The Addon is the end of the trail.
            url = None
        crumbs.append((url, queues[queue]))

    if items:
        crumbs.extend(items)
    return mkt_breadcrumbs(context, items=crumbs, add_default=True)
Ejemplo n.º 22
0
 def description(self, category):
     """Description for the feed as a whole"""
     if category:
         # L10n: %s is a category name.
         return _(u'%s Add-ons') % category.name
     else:
         return _('Extensions')
Ejemplo n.º 23
0
    def is_valid(self, fatal=True):
        """
        Runs some overall archive checks.
        fatal: if the archive is not valid and fatal is True, it will raise
               an error, otherwise it will return False.
        """
        try:
            zip = zipfile.ZipFile(self.source, self.mode)
        except (BadZipfile, IOError):
            if fatal:
                log.info('Error extracting', exc_info=True)
                raise
            return False

        _info = zip.infolist()

        for info in _info:
            if '..' in info.filename or info.filename.startswith('/'):
                log.error('Extraction error, Invalid archive: %s' %
                          self.source)
                raise forms.ValidationError(_('Invalid archive.'))

            if info.file_size > settings.FILE_UNZIP_SIZE_LIMIT:
                log.error('Extraction error, file too big: %s, %s'
                          % (self.source, info.file_size))
                raise forms.ValidationError(_('Invalid archive.'))

        self.info = _info
        self.zip = zip
        return True
Ejemplo n.º 24
0
def preload_submit(request, addon_id, addon):
    if request.method == "POST":
        form = PreloadTestPlanForm(request.POST, request.FILES)
        if form.is_valid():
            # Save test plan file.
            test_plan = request.FILES["test_plan"]

            # Figure the type to save it as (cleaned as pdf/xls from the form).
            filetype = mimetypes.guess_type(test_plan.name)[0]
            if "pdf" in filetype:
                filename = "test_plan_%s.pdf"
            else:
                filename = "test_plan_%s.xls"

            # Timestamp.
            filename = filename % str(time.time()).split(".")[0]
            save_test_plan(request.FILES["test_plan"], filename, addon)

            # Log test plan.
            PreloadTestPlan.objects.filter(addon=addon).update(status=amo.STATUS_DISABLED)
            PreloadTestPlan.objects.create(addon=addon, filename=filename)

            messages.success(request, _("Application for preload successfully submitted."))
            return redirect(addon.get_dev_url("versions"))
        else:
            messages.error(request, _("There was an error with the form."))
    else:
        form = PreloadTestPlanForm()

    return render(request, "developers/apps/preload/submit.html", {"addon": addon, "form": form})
Ejemplo n.º 25
0
    def get_json_data(self, fileorpath):
        path = get_filepath(fileorpath)
        if zipfile.is_zipfile(path):
            zf = SafeUnzip(path)
            zf.is_valid()  # Raises forms.ValidationError if problems.
            try:
                data = zf.extract_path('manifest.webapp')
            except KeyError:
                raise forms.ValidationError(
                    _('The file "manifest.webapp" was not found at the root '
                      'of the packaged app archive.'))
        else:
            file_ = get_file(fileorpath)
            data = file_.read()
            file_.close()

        try:
            enc_guess = chardet.detect(data)
            data = strip_bom(data)
            decoded_data = data.decode(enc_guess['encoding'])
        except (ValueError, UnicodeDecodeError) as exc:
            msg = 'Error parsing webapp %r (encoding: %r %.2f%% sure): %s: %s'
            log.error(msg % (fileorpath, enc_guess['encoding'],
                             enc_guess['confidence'] * 100.0,
                             exc.__class__.__name__, exc))
            raise forms.ValidationError(
                _('Could not decode the webapp manifest file.'))

        try:
            return json.loads(decoded_data)
        except Exception:
            raise forms.ValidationError(
                _('The webapp manifest is not valid JSON.'))
Ejemplo n.º 26
0
def del_image_async(request, image_id):
    """Delete an image given its object id."""
    user = request.user
    if not user.is_authenticated():
        message = _('You are not logged in.')
        return HttpResponseForbidden(
            json.dumps({'status': 'error', 'message': message}))

    try:
        image = ImageAttachment.objects.get(pk=image_id)
    except ImageAttachment.DoesNotExist:
        message = _('The requested image could not be found.')
        return HttpResponseNotFound(
            json.dumps({'status': 'error', 'message': message}))

    if not ((user == image.creator) or
            (user.has_perm('upload.delete_imageattachment'))):
        message = _('You do not have permission to do that.')
        return HttpResponseForbidden(
            json.dumps({'status': 'error', 'message': message}))

    image.file.delete()
    if image.thumbnail:
        image.thumbnail.delete()
    image.delete()

    return HttpResponse(json.dumps({'status': 'success'}))
Ejemplo n.º 27
0
def sidebar(app):
    """Populates the sidebar with (categories, types)."""
    from addons.models import Category
    if app is None:
        return [], []

    # We muck with query to make order_by and extra_order_by play nice.
    q = Category.objects.filter(application=app.id, weight__gte=0,
                                type=amo.ADDON_EXTENSION)
    categories = order_by_translation(q, 'name')
    categories.query.extra_order_by.insert(0, 'weight')

    Type = collections.namedtuple('Type', 'id name url')
    base = urlresolvers.reverse('home')
    types = [Type(99, _('Collections'), base + 'collections/')]

    shown_types = {
        amo.ADDON_PERSONA: urlresolvers.reverse('browse.personas'),
        amo.ADDON_DICT: urlresolvers.reverse('browse.language-tools'),
        amo.ADDON_SEARCH: urlresolvers.reverse('browse.search-tools'),
        amo.ADDON_THEME: urlresolvers.reverse('browse.themes'),
    }
    titles = dict(amo.ADDON_TYPES,
                  **{amo.ADDON_DICT: _('Dictionaries & Language Packs')})
    for type_, url in shown_types.items():
        if type_ in app.types:
            types.append(Type(type_, titles[type_], url))

    return categories, sorted(types, key=lambda x: x.name)
Ejemplo n.º 28
0
    def is_compatible(self):
        """Returns tuple of compatibility and reasons why if not.

        Server side conditions for determining compatibility are:
            * The add-on is an extension (not a theme, app, etc.)
            * Has not opted in to strict compatibility.
            * Does not use binary_components in chrome.manifest.

        Note: The lowest maxVersion compat check needs to be checked
              separately.
        Note: This does not take into account the client conditions.

        """
        compat = True
        reasons = []
        if self.addon.type != amo.ADDON_EXTENSION:
            compat = False
            # TODO: We may want this. For now we think it may be confusing.
            # reasons.append(_('Add-on is not an extension.'))
        if self.files.filter(binary_components=True).exists():
            compat = False
            reasons.append(_("Add-on uses binary components."))
        if self.files.filter(strict_compatibility=True).exists():
            compat = False
            reasons.append(_("Add-on has opted into strict compatibility " "checking."))
        return (compat, reasons)
Ejemplo n.º 29
0
def up_image_async(request, model_name, object_pk):
    """Upload all images in request.FILES."""

    # Verify the model agaist our white-list
    if model_name not in ALLOWED_MODELS:
        message = _('Model not allowed.')
        return HttpResponseBadRequest(
            json.dumps({'status': 'error', 'message': message}))

    # Get the model
    m = get_model(*model_name.split('.'))

    # Then look up the object by pk
    try:
        obj = m.objects.get(pk=object_pk)
    except ObjectDoesNotExist:
        message = _('Object does not exist.')
        return HttpResponseNotFound(
            json.dumps({'status': 'error', 'message': message}))

    try:
        file_info = upload_imageattachment(request, obj)
    except FileTooLargeError as e:
        return HttpResponseBadRequest(
            json.dumps({'status': 'error', 'message': e.args[0]}))

    if isinstance(file_info, dict) and 'thumbnail_url' in file_info:
        return HttpResponse(
            json.dumps({'status': 'success', 'file': file_info}))

    message = _('Invalid or no image received.')
    return HttpResponseBadRequest(
        json.dumps({'status': 'error', 'message': message,
                    'errors': file_info}))
Ejemplo n.º 30
0
    def clean(self):
        # If lng/lat were provided, make sure they point at a country somewhere...
        if self.cleaned_data.get('lat') is not None and self.cleaned_data.get('lng') is not None:
            # We only want to call reverse_geocode if some location data changed.
            if ('lat' in self.changed_data or 'lng' in self.changed_data or
                    'saveregion' in self.changed_data or 'savecity' in self.changed_data):
                self.instance.lat = self.cleaned_data['lat']
                self.instance.lng = self.cleaned_data['lng']
                self.instance.reverse_geocode()
                if not self.instance.geo_country:
                    error_msg = _('Location must be inside a country.')
                    self.errors['savecountry'] = self.error_class([error_msg])
                    del self.cleaned_data['savecountry']
                # If the user doesn't want their region/city saved, respect it.
                if not self.cleaned_data.get('saveregion'):
                    if not self.cleaned_data.get('savecity'):
                        self.instance.geo_region = None
                    else:
                        error_msg = _('Region must also be saved if city is saved.')
                        self.errors['saveregion'] = self.error_class([error_msg])

                if not self.cleaned_data.get('savecity'):
                    self.instance.geo_city = None
        else:
            self.errors['location'] = self.error_class([_('Search for your country on the map.')])
            self.errors['savecountry'] = self.error_class([_('Country cannot be empty.')])
            del self.cleaned_data['savecountry']

        return self.cleaned_data
Ejemplo n.º 31
0
class EDIT_DESCRIPTIONS(_LOG):
    id = 3
    action_class = 'edit'
    format = _(u'{addon} description edited.')
Ejemplo n.º 32
0
class MANIFEST_UPDATED(_LOG):
    id = 52
    format = _(u'{addon} manifest updated.')
Ejemplo n.º 33
0
class PAYPAL_FAILED(_LOG):
    id = 51
    format = _(u'{addon} failed checks with PayPal.')
Ejemplo n.º 34
0
class CHANGE_PASSWORD(_LOG):
    id = 48
    format = _(u'Password changed.')
Ejemplo n.º 35
0
class BULK_VALIDATION_USER_EMAILED(_LOG):
    id = 130
    format = _(u'Email sent to Author about add-on compatibility.')
Ejemplo n.º 36
0
class BULK_VALIDATION_EMAILED(_LOG):
    id = 47
    format = _(u'Authors emailed about compatibility of {version}.')
Ejemplo n.º 37
0
class MAX_APPVERSION_UPDATED(_LOG):
    id = 46
    format = _(u'Application max version for {version} updated.')
Ejemplo n.º 38
0
class CHANGE_POLICY(_LOG):
    id = 38
    action_class = 'edit'
    format = _(u'{addon} policy changed.')
Ejemplo n.º 39
0
class CHANGE_USER_WITH_ROLE(_LOG):
    """ Expects: author.user, role, addon """
    id = 36
    # L10n: {0} is a user, {1} is their role
    format = _(u'{0.name} role changed to {1} for {addon}.')
    keep = True
Ejemplo n.º 40
0
class CHANGE_ICON(_LOG):
    id = 39
    action_class = 'edit'
    format = _(u'{addon} icon changed.')
Ejemplo n.º 41
0
class REMOVE_RECOMMENDED(_LOG):
    id = 34
    format = _(u'{addon} is no longer featured.')
    keep = True
Ejemplo n.º 42
0
class CHANGE_LICENSE(_LOG):
    """ Expects: license, addon """
    id = 37
    action_class = 'edit'
    format = _(u'{addon} is now licensed under {0.name}.')
Ejemplo n.º 43
0
class REMOVE_RECOMMENDED_CATEGORY(_LOG):
    id = 32
    action_class = 'edit'
    # L10n: {0} is a category name.
    format = _(u'{addon} no longer featured in {0}.')
Ejemplo n.º 44
0
class ADD_APPVERSION(_LOG):
    id = 35
    action_class = 'add'
    # L10n: {0} is the application, {1} is the version of the app
    format = _(u'{0} {1} added.')
Ejemplo n.º 45
0
class EDIT_PROPERTIES(_LOG):
    """ Expects: addon """
    id = 2
    action_class = 'edit'
    format = _(u'{addon} properties edited.')
Ejemplo n.º 46
0
class ADD_RECOMMENDED(_LOG):
    id = 33
    format = _(u'{addon} is now featured.')
    keep = True
Ejemplo n.º 47
0
class REMOVE_FROM_COLLECTION(_LOG):
    id = 28
    action_class = 'collection'
    format = _(u'{addon} removed from {collection}.')
Ejemplo n.º 48
0
class ADD_RECOMMENDED_CATEGORY(_LOG):
    id = 31
    action_class = 'edit'
    # L10n: {0} is a category name.
    format = _(u'{addon} featured in {0}.')
Ejemplo n.º 49
0
class REMOVE_TAG(_LOG):
    id = 26
    action_class = 'tag'
    format = _(u'{tag} removed from {addon}.')
Ejemplo n.º 50
0
class ADD_REVIEW(_LOG):
    id = 29
    action_class = 'review'
    format = _(u'{review} for {addon} written.')
Ejemplo n.º 51
0
class REQUEST_SUPER_REVIEW(_LOG):
    id = 45
    format = _(u'{addon} {version} super review requested.')
    short = _(u'Super review requested')
    keep = True
    review_queue = True
Ejemplo n.º 52
0
class ADD_TO_COLLECTION(_LOG):
    id = 27
    action_class = 'collection'
    format = _(u'{addon} added to {collection}.')
Ejemplo n.º 53
0
class ADD_FILE_TO_VERSION(_LOG):
    id = 19
    action_class = 'add'
    format = _(u'File {0.name} added to {version} of {addon}.')
Ejemplo n.º 54
0
class ADD_TAG(_LOG):
    id = 25
    action_class = 'tag'
    format = _(u'{tag} added to {addon}.')
Ejemplo n.º 55
0
class ADD_VERSION(_LOG):
    id = 16
    action_class = 'add'
    format = _(u'{version} added to {addon}.')
    keep = True
Ejemplo n.º 56
0
class CREATE_ADDON(_LOG):
    id = 1
    action_class = 'add'
    format = _(u'{addon} was created.')
    keep = True
Ejemplo n.º 57
0
class EDIT_PREVIEW(_LOG):
    id = 14
    action_class = 'edit'
    format = _(u'Preview edited for {addon}.')
Ejemplo n.º 58
0
class EDIT_VERSION(_LOG):
    id = 17
    action_class = 'edit'
    format = _(u'{version} edited for {addon}.')
Ejemplo n.º 59
0
class ADD_PREVIEW(_LOG):
    id = 13
    action_class = 'add'
    format = _(u'Preview added to {addon}.')
Ejemplo n.º 60
0
class DELETE_PREVIEW(_LOG):
    id = 15
    action_class = 'delete'
    format = _(u'Preview deleted from {addon}.')