Esempio n. 1
0
def add(request):
    "Displays/processes a form to create a collection."
    data = {}
    if request.method == 'POST':
        form = forms.CollectionForm(
                request.POST, request.FILES,
                initial=initial_data_from_request(request))
        aform = forms.AddonsForm(request.POST)
        if form.is_valid():
            collection = form.save(default_locale=request.LANG)
            collection.save()
            if aform.is_valid():
                aform.save(collection)

            title = _("Collection created!")
            msg = _("""Your new collection is shown below. You can <a
                       href="%(url)s">edit additional settings</a> if you'd
                       like.""") % {'url': collection.edit_url()}
            messages.success(request, title, msg, extra_tags='collection',
                             message_safe=True)
            log.info('Created collection %s' % collection.id)
            return http.HttpResponseRedirect(collection.get_url_path())
        else:
            data['addons'] = Addon.objects.filter(pk__in=aform.clean_addon())
            data['comments'] = aform.clean_addon_comment()
    else:
        form = forms.CollectionForm()

    data.update(form=form, filter=get_filter(request))
    return render(request, 'bandwagon/add.html', data)
Esempio n. 2
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})
Esempio n. 3
0
def monthly_pick(request):
    form = MonthlyPickFormSet(request.POST or None)
    if request.method == 'POST' and form.is_valid():
        form.save()
        messages.success(request, 'Changes successfully saved.')
        return redirect('zadmin.monthly_pick')
    return jingo.render(request, 'zadmin/monthly_pick.html', dict(form=form))
Esempio n. 4
0
def edit(request):
    webapp = settings.APP_PREVIEW
    # Don't use request.amo_user since it has too much caching.
    amouser = UserProfile.objects.get(pk=request.user.id)
    if request.method == 'POST':
        # ModelForm alters the instance you pass in.  We need to keep a copy
        # around in case we need to use it below (to email the user)
        original_email = amouser.email
        form = forms.UserEditForm(request.POST, request.FILES, request=request,
                                  instance=amouser, webapp=webapp)
        if form.is_valid():
            messages.success(request, _('Profile Updated'))
            if amouser.email != original_email:
                # Temporarily block email changes.
                if settings.APP_PREVIEW:
                    messages.error(request, 'Error',
                                   'You cannot change your email on the '
                                   'developer preview site.')
                    return jingo.render(request, 'users/edit.html',
                                        {'form': form, 'amouser': amouser})

                l = {'user': amouser,
                     'mail1': original_email,
                     'mail2': amouser.email}
                log.info(u"User (%(user)s) has requested email change from"
                          "(%(mail1)s) to (%(mail2)s)" % l)
                messages.info(request, _('Email Confirmation Sent'),
                    _(u'An email has been sent to {0} to confirm your new '
                       'email address. For the change to take effect, you '
                       'need to click on the link provided in this email. '
                       'Until then, you can keep logging in with your '
                       'current email address.').format(amouser.email))

                domain = settings.DOMAIN
                token, hash = EmailResetCode.create(amouser.id, amouser.email)
                url = "%s%s" % (settings.SITE_URL,
                                reverse('users.emailchange', args=[amouser.id,
                                                                token, hash]))
                t = loader.get_template('users/email/emailchange.ltxt')
                c = {'domain': domain, 'url': url}
                send_mail(_('Please confirm your email address '
                            'change at %s' % domain),
                    t.render(Context(c)), None, [amouser.email],
                    use_blacklist=False, real_email=True)

                # Reset the original email back.  We aren't changing their
                # address until they confirm the new one
                amouser.email = original_email
            form.save()
            return redirect('users.edit')
        else:

            messages.error(request, _('Errors Found'),
                                    _('There were errors in the changes '
                                      'you made. Please correct them and '
                                      'resubmit.'))
    else:
        form = forms.UserEditForm(instance=amouser, webapp=webapp)
    return jingo.render(request, 'users/edit.html',
                        {'form': form, 'amouser': amouser, 'webapp': webapp})
Esempio n. 5
0
def refund_reason(request, contribution, wizard):
    addon = contribution.addon
    if not 'request' in wizard.get_progress():
        return redirect('users.support', contribution.pk, 'request')

    if contribution.is_instant_refund():
        paypal.refund(contribution.paykey)
        paypal_log.info('Refund issued for contribution %r' % contribution.pk)
        # Note: we have to wait for PayPal to issue an IPN before it's
        # completely refunded.
        messages.success(request, _('Refund is being processed.'))
        return redirect('users.purchases')

    form = forms.ContactForm(request.POST or None)
    if request.method == 'POST' and form.is_valid():
        url = absolutify(urlparams(addon.get_dev_url('issue_refund'),
                                   transaction_id=contribution.transaction_id))
        template = jingo.render_to_string(request,
            wizard.tpl('emails/refund-request.txt'),
            context={'addon': addon,
                     'form': form,
                     'user': request.amo_user,
                     'contribution': contribution,
                     'refund_url': url})
        log.info('Refund request sent by user: %s for addon: %s' %
                 (request.amo_user.pk, addon.pk))
        # L10n: %s is the addon name.
        send_mail(_(u'New Refund Request for %s' % addon.name),
                  template, settings.NOBODY_EMAIL,
                  [smart_str(addon.support_email)])
        return redirect(reverse('users.support',
                                args=[contribution.pk, 'refund-sent']))

    return wizard.render(request, wizard.tpl('refund.html'), {'form': form})
Esempio n. 6
0
def paypal_setup(request, addon_id, addon, webapp):
    if addon.premium_type == amo.ADDON_FREE:
        messages.error(request, 'Your app does not use payments.')
        return redirect(addon.get_dev_url('payments'))

    paypal_form = PaypalSetupForm(request.POST or None)
    currency_form = CurrencyForm(request.POST or None,
                        initial={'currencies': addon.premium.currencies
                                               if addon.premium else {}})

    context = {'addon': addon, 'paypal_form': paypal_form,
               'currency_form': currency_form}

    if request.POST.get('form') == 'paypal' and paypal_form.is_valid():
        existing = paypal_form.cleaned_data['business_account']
        if existing != 'yes':
            # Go create an account.
            # TODO: this will either become the API or something some better
            # URL for the future.
            return redirect(settings.PAYPAL_CGI_URL)
        else:
            # Go setup your details on paypal.
            addon.update(paypal_id=paypal_form.cleaned_data['email'])
            if addon.premium and addon.premium.paypal_permissions_token:
                addon.premium.update(paypal_permissions_token='')
            return redirect(addon.get_dev_url('paypal_setup_bounce'))

    if request.POST.get('form') == 'currency' and currency_form.is_valid():
        currencies = currency_form.cleaned_data['currencies']
        addon.premium.update(currencies=currencies)
        messages.success(request, _('Currencies updated.'))
        return redirect(addon.get_dev_url('paypal_setup'))

    return jingo.render(request, 'developers/payments/paypal-setup.html',
                        context)
Esempio n. 7
0
def issue_refund(request, addon_id, addon, webapp=False):
    txn_id = request.REQUEST.get('transaction_id')
    if not txn_id:
        raise http.Http404
    form_enabled = True
    contribution = get_object_or_404(Contribution, transaction_id=txn_id,
                                     type__in=[amo.CONTRIB_PURCHASE,
                                               amo.CONTRIB_INAPP])

    if (hasattr(contribution, 'refund') and
        contribution.refund.status not in (amo.REFUND_PENDING,
                                           amo.REFUND_FAILED)):
        # If it's not pending, we've already taken action.
        messages.error(request, _('Refund already processed.'))
        form_enabled = False

    elif request.method == 'POST':
        if 'issue' in request.POST:
            try:
                results = paypal.refund(contribution.paykey)
            except PaypalError, e:
                contribution.record_failed_refund(e)
                paypal_log.error('Refund failed for: %s' % txn_id,
                                 exc_info=True)
                messages.error(request, _('There was an error with '
                                          'the refund.'))
                return redirect(addon.get_dev_url('refunds'))

            for res in results:
                if res['refundStatus'] == 'ALREADY_REVERSED_OR_REFUNDED':
                    paypal_log.debug(
                        'Refund attempt for already-refunded paykey: %s, %s' %
                        (contribution.paykey, res['receiver.email']))
                    messages.error(request, _('Refund was previously issued; '
                                              'no action taken.'))
                    return redirect(addon.get_dev_url('refunds'))
                elif res['refundStatus'] == 'NO_API_ACCESS_TO_RECEIVER':
                    paypal_log.debug('Refund attempt for product %s with no '
                                     'refund token: %s, %s' %
                                    (contribution.addon.pk,
                                     contribution.paykey,
                                     res['receiver.email']))
                    messages.error(request,
                        _("A refund can't be issued at this time. We've "
                          "notified an admin; please try again later."))
                    return redirect(addon.get_dev_url('refunds'))

            contribution.mail_approved()
            refund = contribution.enqueue_refund(amo.REFUND_APPROVED)
            paypal_log.info('Refund %r issued for contribution %r' %
                            (refund.pk, contribution.pk))
            messages.success(request, _('Refund issued.'))
        else:
            contribution.mail_declined()
            # TODO: Consider requiring a rejection reason for declined refunds.
            refund = contribution.enqueue_refund(amo.REFUND_DECLINED)
            paypal_log.info('Refund %r declined for contribution %r' %
                            (refund.pk, contribution.pk))
            messages.success(request, _('Refund declined.'))
        return redirect(addon.get_dev_url('refunds'))
Esempio n. 8
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})
Esempio n. 9
0
def version_delete(request, addon_id, addon):
    version_id = request.POST.get('version_id')
    version = get_object_or_404(Version, pk=version_id, addon=addon)
    version.delete()
    messages.success(request,
                     _('Version "{0}" deleted.').format(version.version))
    return redirect(addon.get_dev_url('versions'))
Esempio n. 10
0
def status(request, addon_id, addon, webapp=False):
    form = forms.AppAppealForm(request.POST, product=addon)
    upload_form = NewWebappForm(request.POST or None, is_packaged=True,
                                addon=addon)

    if request.method == 'POST':
        if 'resubmit-app' in request.POST and form.is_valid():
            form.save()
            messages.success(request, _('App successfully resubmitted.'))
            return redirect(addon.get_dev_url('versions'))

        elif 'upload-version' in request.POST and upload_form.is_valid():
            ver = Version.from_upload(upload_form.cleaned_data['upload'],
                                      addon, [amo.PLATFORM_ALL])
            log.info('[Webapp:%s] New version created id=%s from upload: %s'
                     % (addon, ver.pk, upload_form.cleaned_data['upload']))
            return redirect(addon.get_dev_url('versions.edit', args=[ver.pk]))

    ctx = {'addon': addon, 'webapp': webapp, 'form': form,
           'upload_form': upload_form}

    if addon.status == amo.STATUS_REJECTED:
        try:
            entry = (AppLog.objects
                     .filter(addon=addon,
                             activity_log__action=amo.LOG.REJECT_VERSION.id)
                     .order_by('-created'))[0]
        except IndexError:
            entry = None
        # This contains the rejection reason and timestamp.
        ctx['rejection'] = entry and entry.activity_log

    return jingo.render(request, 'developers/apps/status.html', ctx)
Esempio n. 11
0
def _refresh_mdn(request):
    if settings.MDN_LAZY_REFRESH and 'refresh' in request.GET:
        # If you can delay this, please teach me. I give up.
        refresh_mdn_cache()
        messages.success(request,
            'Pulling new content from MDN. Please check back in a few minutes.'
            ' Thanks for all your awesome work! Devs appreciate it!')
Esempio n. 12
0
def hera(request):
    form = FlushForm(initial={'flushprefix': settings.SITE_URL})

    boxes = []
    configured = False  # Default to not showing the form.
    for i in settings.HERA:
        hera = get_hera(i)
        r = {'location': urlparse(i['LOCATION'])[1], 'stats': False}
        if hera:
            r['stats'] = hera.getGlobalCacheInfo()
            configured = True
        boxes.append(r)

    if not configured:
        messages.error(request, "Hera is not (or mis-)configured.")
        form = None

    if request.method == 'POST' and hera:
        form = FlushForm(request.POST)
        if form.is_valid():
            expressions = request.POST['flushlist'].splitlines()

            for url in expressions:
                num = flush_urls([url], request.POST['flushprefix'], True)
                msg = ("Flushed %d objects from front end cache for: %s"
                       % (len(num), url))
                log.info("[Hera] (user:%s) %s" % (request.user, msg))
                messages.success(request, msg)

    return jingo.render(request, 'zadmin/hera.html',
                        {'form': form, 'boxes': boxes})
Esempio n. 13
0
def hera(request):
    form = FlushForm(initial={"flushprefix": site_settings.SITE_URL})

    boxes = []
    configured = False  # Default to not showing the form.
    for i in site_settings.HERA:
        hera = get_hera(i)
        r = {"location": urlparse(i["LOCATION"])[1], "stats": False}
        if hera:
            r["stats"] = hera.getGlobalCacheInfo()
            configured = True
        boxes.append(r)

    if not configured:
        messages.error(request, "Hera is not (or mis-)configured.")
        form = None

    if request.method == "POST" and hera:
        form = FlushForm(request.POST)
        if form.is_valid():
            expressions = request.POST["flushlist"].splitlines()

            for url in expressions:
                num = flush_urls([url], request.POST["flushprefix"], True)
                msg = "Flushed %d objects from front end cache for: %s" % (len(num), url)
                log.info("[Hera] (user:%s) %s" % (request.user, msg))
                messages.success(request, msg)

    return jingo.render(request, "zadmin/hera.html", {"form": form, "boxes": boxes})
Esempio n. 14
0
def ownership(request, addon_id, addon, webapp=False):
    # Authors.
    qs = AddonUser.objects.filter(addon=addon).order_by('position')
    user_form = forms.AuthorFormSet(request.POST or None, queryset=qs)

    if request.method == 'POST' and user_form.is_valid():
        # Authors.
        authors = user_form.save(commit=False)
        for author in authors:
            action = None
            if not author.id or author.user_id != author._original_user_id:
                action = amo.LOG.ADD_USER_WITH_ROLE
                author.addon = addon
            elif author.role != author._original_role:
                action = amo.LOG.CHANGE_USER_WITH_ROLE

            author.save()
            if action:
                amo.log(action, author.user, author.get_role_display(), addon)
            if (author._original_user_id and
                author.user_id != author._original_user_id):
                amo.log(amo.LOG.REMOVE_USER_WITH_ROLE,
                        (UserProfile, author._original_user_id),
                        author.get_role_display(), addon)

        for author in user_form.deleted_objects:
            amo.log(amo.LOG.REMOVE_USER_WITH_ROLE, author.user,
                    author.get_role_display(), addon)

        messages.success(request, _('Changes successfully saved.'))

        return redirect(addon.get_dev_url('owner'))

    ctx = dict(addon=addon, webapp=webapp, user_form=user_form)
    return jingo.render(request, 'developers/apps/owner.html', ctx)
Esempio n. 15
0
def in_app_config(request, addon_id, addon, webapp=True):
    if addon.premium_type not in amo.ADDON_INAPPS:
        messages.error(request, 'Your app does not use payments.')
        return redirect(addon.get_dev_url('payments'))

    try:
        inapp_config = InappConfig.objects.get(addon=addon,
                                               status=amo.INAPP_STATUS_ACTIVE)
    except models.ObjectDoesNotExist:
        inapp_config = None

    inapp_form = InappConfigForm(request.POST or None,
                                 instance=inapp_config)

    if request.method == 'POST' and inapp_form.is_valid():
        new_inapp = inapp_form.save(commit=False)
        new_inapp.addon = addon
        new_inapp.status = amo.INAPP_STATUS_ACTIVE
        if not new_inapp.public_key:
            new_inapp.public_key = InappConfig.generate_public_key()
        new_inapp.save()
        if not new_inapp.has_private_key():
            new_inapp.set_private_key(InappConfig.generate_private_key())

        messages.success(request, _('Changes successfully saved.'))
        return redirect(addon.get_dev_url('in_app_config'))

    return jingo.render(request, 'developers/payments/in-app-config.html',
                        dict(addon=addon, inapp_form=inapp_form,
                             inapp_config=inapp_config))
Esempio n. 16
0
def paypal_setup_confirm(request, addon_id, addon, webapp, source='paypal'):
    # If you bounce through paypal as you do permissions changes set the
    # source to paypal.
    if source == 'paypal':
        msg = _('PayPal set up complete.')
        title = _('Confirm Details')
        button = _('Continue')
    # If you just hit this page from the Manage Paypal, show some less
    # wizardy stuff.
    else:
        msg = _('Changes saved.')
        title = _('Contact Details')
        button = _('Save')

    adp, created = AddonPaymentData.objects.safer_get_or_create(addon=addon)
    form = forms.PaypalPaymentData(request.POST or None, instance=adp)
    if request.method == 'POST' and form.is_valid():
        adp.update(**form.cleaned_data)
        messages.success(request, msg)
        if source == 'paypal' and addon.is_incomplete() and addon.paypal_id:
            addon.mark_done()
        return redirect(addon.get_dev_url('paypal_setup'))

    return jingo.render(request,
                        'developers/payments/paypal-details-confirm.html',
                        {'addon': addon, 'button': button, 'form': form,
                         'title': title})
Esempio n. 17
0
def features(request):
    form = FeaturedCollectionFormSet(request.POST or None)
    if request.method == 'POST' and form.is_valid():
        form.save(commit=False)
        messages.success(request, 'Changes successfully saved.')
        return redirect('zadmin.features')
    return jingo.render(request, 'zadmin/features.html', dict(form=form))
Esempio n. 18
0
def issue_refund(request, addon_id, addon, webapp=False):
    txn_id = request.REQUEST.get("transaction_id")
    if not txn_id:
        raise http.Http404
    form_enabled = True
    contribution = get_object_or_404(
        Contribution, transaction_id=txn_id, type__in=[amo.CONTRIB_PURCHASE, amo.CONTRIB_INAPP]
    )

    if hasattr(contribution, "refund") and contribution.refund.status not in (amo.REFUND_PENDING, amo.REFUND_FAILED):
        # If it's not pending, we've already taken action.
        messages.error(request, _("Refund already processed."))
        form_enabled = False

    elif request.method == "POST":
        if "issue" in request.POST:
            if waffle.flag_is_active(request, "solitude-payments"):
                try:
                    response = client.post_refund(data={"uuid": contribution.transaction_id})
                except client.Error, e:
                    contribution.record_failed_refund(e)
                    paypal_log.error("Refund failed for: %s" % txn_id, exc_info=True)
                    messages.error(request, _("There was an error with " "the refund."))
                    return redirect(addon.get_dev_url("refunds"))
                results = response["response"]

            else:
                # TODO(solitude): remove this.
                try:
                    results = paypal.refund(contribution.paykey)
                except PaypalError, e:
                    contribution.record_failed_refund(e)
                    paypal_log.error("Refund failed for: %s" % txn_id, exc_info=True)
                    messages.error(request, _("There was an error with " "the refund."))
                    return redirect(addon.get_dev_url("refunds"))

            for res in results:
                if res["refundStatus"] == "ALREADY_REVERSED_OR_REFUNDED":
                    paypal_log.debug(
                        "Refund attempt for already-refunded paykey: %s, %s"
                        % (contribution.paykey, res["receiver.email"])
                    )
                    messages.error(request, _("Refund was previously issued; " "no action taken."))
                    return redirect(addon.get_dev_url("refunds"))
                elif res["refundStatus"] == "NO_API_ACCESS_TO_RECEIVER":
                    paypal_log.debug(
                        "Refund attempt for product %s with no "
                        "refund token: %s, %s" % (contribution.addon.pk, contribution.paykey, res["receiver.email"])
                    )
                    messages.error(
                        request,
                        _("A refund can't be issued at this time. We've " "notified an admin; please try again later."),
                    )
                    return redirect(addon.get_dev_url("refunds"))

            contribution.mail_approved()
            amo.log(amo.LOG.REFUND_GRANTED, addon, contribution.user)
            refund = contribution.enqueue_refund(amo.REFUND_APPROVED)
            paypal_log.info("Refund %r issued for contribution %r" % (refund.pk, contribution.pk))
            messages.success(request, _("Refund issued."))
Esempio n. 19
0
def payments(request, addon_id, addon):
    charity = None if addon.charity_id == amo.FOUNDATION_ORG else addon.charity
    charity_form = forms.CharityForm(request.POST or None, instance=charity,
                                     prefix='charity')
    contrib_form = forms.ContribForm(request.POST or None, instance=addon,
                                     initial=forms.ContribForm.initial(addon))
    profile_form = forms.ProfileForm(request.POST or None, instance=addon,
                                     required=True)
    if request.method == 'POST':
        if contrib_form.is_valid():
            addon = contrib_form.save(commit=False)
            addon.wants_contributions = True
            valid = _save_charity(addon, contrib_form, charity_form)
            if not addon.has_full_profile():
                valid &= profile_form.is_valid()
                if valid:
                    profile_form.save()
            if valid:
                addon.save()
                messages.success(request, _('Changes successfully saved.'))
                amo.log(amo.LOG.EDIT_CONTRIBUTIONS, addon)

                return redirect('devhub.addons.payments', addon.slug)
    errors = charity_form.errors or contrib_form.errors or profile_form.errors
    if errors:
        messages.error(request, _('There were errors in your submission.'))
    return jingo.render(request, 'devhub/addons/payments.html',
        dict(addon=addon, charity_form=charity_form, errors=errors,
             contrib_form=contrib_form, profile_form=profile_form))
Esempio n. 20
0
def payments(request, addon_id, addon):
    charity = None if addon.charity_id == amo.FOUNDATION_ORG else addon.charity
    charity_form = forms.CharityForm(request.POST or None, instance=charity,
                                     prefix='charity')
    contrib_form = forms.ContribForm(request.POST or None, instance=addon,
                                     initial=forms.ContribForm.initial(addon))
    if request.method == 'POST':
        if contrib_form.is_valid():
            addon, valid = contrib_form.save(commit=False), True
            addon.wants_contributions = True
            recipient = contrib_form.cleaned_data['recipient']
            if recipient == 'dev':
                addon.charity = None
            elif recipient == 'moz':
                addon.charity_id = amo.FOUNDATION_ORG
            elif recipient == 'org':
                valid = charity_form.is_valid()
                if valid:
                    addon.charity = charity_form.save()
            if valid:
                addon.save()
                messages.success(request, _('Changes successfully saved.'))
                return redirect('devhub.addons.payments', addon_id)
    if charity_form.errors or contrib_form.errors:
        messages.error(request, _('There were errors in your submission.'))
    return jingo.render(request, 'devhub/addons/payments.html',
                        dict(addon=addon, charity_form=charity_form,
                            contrib_form=contrib_form))
Esempio n. 21
0
def spam(request):
    if not acl.action_allowed(request, 'Spam', 'Flag'):
        raise PermissionDenied
    spam = Spam()

    if request.method == 'POST':
        review = Review.objects.get(pk=request.POST['review'])
        if 'del_review' in request.POST:
            log.info('SPAM: %s' % review.id)
            delete(request, request.POST['addon'], review.id)
            messages.success(request, 'Deleted that review.')
        elif 'del_user' in request.POST:
            user = review.user
            log.info('SPAMMER: %s deleted %s' %
                     (request.amo_user.username, user.username))
            if not user.is_developer:
                Review.objects.filter(user=user).delete()
                user.anonymize()
            messages.success(request, 'Deleted that dirty spammer.')

        for reason in spam.reasons():
            spam.redis.srem(reason, review.id)
        return http.HttpResponseRedirect(request.path)

    buckets = {}
    for reason in spam.reasons():
        ids = spam.redis.smembers(reason)
        key = reason.split(':')[-1]
        buckets[key] = Review.objects.no_cache().filter(id__in=ids)
    reviews = dict((review.addon_id, review) for bucket in buckets.values()
                                             for review in bucket)
    for addon in Addon.objects.no_cache().filter(id__in=reviews):
        reviews[addon.id].addon = addon
    return render(request, 'reviews/spam.html',
                  dict(buckets=buckets, review_perms=dict(is_admin=True)))
Esempio n. 22
0
def content_ratings_edit(request, addon_id, addon):
    initial = {}
    try:
        app_info = addon.iarc_info
        initial['submission_id'] = app_info.submission_id
        initial['security_code'] = app_info.security_code
    except IARCInfo.DoesNotExist:
        pass

    form = IARCGetAppInfoForm(data=request.POST or None, initial=initial)

    if request.method == 'POST' and form.is_valid():
        try:
            form.save(addon)
            messages.success(request, _('Content ratings successfully saved.'))
            return redirect(addon.get_dev_url('ratings'))
        except django_forms.ValidationError:
            pass  # Fall through to show the form error.

    with amo.utils.no_translation(addon.default_locale):
        addon_delocalized = Addon.objects.get(pk=addon.pk)

    return jingo.render(
        request, 'developers/apps/ratings/ratings_edit.html', {
            'addon': addon,
            'app_name': addon_delocalized.name,
            'form': form,
            'now': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        })
Esempio n. 23
0
def api(request):
    roles = request.amo_user.groups.filter(name='Admins').exists()
    f = APIConsumerForm()
    if roles:
        messages.error(request,
                       _('Users with the admin role cannot use the API.'))

    elif request.method == 'POST':
        if 'delete' in request.POST:
            try:
                consumer = Access.objects.get(pk=request.POST.get('consumer'))
                consumer.delete()
            except Access.DoesNotExist:
                messages.error(request, _('No such API key.'))
        else:
            key = 'mkt:%s:%s:%s' % (
                request.amo_user.pk,
                request.amo_user.email,
                Access.objects.filter(user=request.user).count())
            access = Access.objects.create(key=key,
                                           user=request.user,
                                           secret=generate())
            f = APIConsumerForm(request.POST, instance=access)
            if f.is_valid():
                f.save()
                messages.success(request, _('New API key generated.'))
            else:
                access.delete()
    consumers = list(Access.objects.filter(user=request.user))
    return jingo.render(request, 'developers/api.html',
                        {'consumers': consumers, 'roles': roles, 'form': f})
Esempio n. 24
0
def email_devs(request):
    form = DevMailerForm(request.POST or None)
    preview = EmailPreviewTopic(topic='email-devs')
    if preview.filter().count():
        preview_csv = reverse('zadmin.email_preview_csv',
                              args=[preview.topic])
    else:
        preview_csv = None
    if request.method == 'POST' and form.is_valid():
        data = form.cleaned_data
        qs = (AddonUser.objects.filter(role__in=(amo.AUTHOR_ROLE_DEV,
                                                 amo.AUTHOR_ROLE_OWNER))
                               .exclude(user__email=None))

        if data['recipients'] in ('payments', 'desktop_apps'):
            qs = qs.exclude(addon__status=amo.STATUS_DELETED)
        else:
            qs = qs.filter(addon__status__in=amo.LISTED_STATUSES)

        if data['recipients'] == 'eula':
            qs = qs.exclude(addon__eula=None)
        elif data['recipients'] in ('payments',
                                    'payments_region_enabled',
                                    'payments_region_disabled'):
            qs = qs.filter(addon__type=amo.ADDON_WEBAPP)
            qs = qs.exclude(addon__premium_type__in=(amo.ADDON_FREE,
                                                     amo.ADDON_OTHER_INAPP))
            if data['recipients'] == 'payments_region_enabled':
                qs = qs.filter(addon__enable_new_regions=True)
            elif data['recipients'] == 'payments_region_disabled':
                qs = qs.filter(addon__enable_new_regions=False)
        elif data['recipients'] == 'apps':
            qs = qs.filter(addon__type=amo.ADDON_WEBAPP)
        elif data['recipients'] == 'desktop_apps':
            qs = (qs.filter(addon__type=amo.ADDON_WEBAPP,
                addon__addondevicetype__device_type=amo.DEVICE_DESKTOP.id))
        elif data['recipients'] == 'sdk':
            qs = qs.exclude(addon__versions__files__jetpack_version=None)
        elif data['recipients'] == 'all_extensions':
            qs = qs.filter(addon__type=amo.ADDON_EXTENSION)
        else:
            raise NotImplementedError('If you want to support emailing other '
                                      'types of developers, do it here!')
        if data['preview_only']:
            # Clear out the last batch of previewed emails.
            preview.filter().delete()
        total = 0
        for emails in chunked(set(qs.values_list('user__email', flat=True)),
                              100):
            total += len(emails)
            tasks.admin_email.delay(emails, data['subject'], data['message'],
                                    preview_only=data['preview_only'],
                                    preview_topic=preview.topic)
        msg = 'Emails queued for delivery: %s' % total
        if data['preview_only']:
            msg = '%s (for preview only, emails not sent!)' % msg
        messages.success(request, msg)
        return redirect('zadmin.email_devs')
    return jingo.render(request, 'zadmin/email-devs.html',
                        dict(form=form, preview_csv=preview_csv))
Esempio n. 25
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'))
Esempio n. 26
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})
Esempio n. 27
0
def featured_apps_admin(request):
    home_collection = Webapp.featured_collection('home')
    category_collection = Webapp.featured_collection('category')

    if request.POST:
        if 'home_submit' in request.POST:
            coll = home_collection
            rowid = 'home'
        elif 'category_submit' in request.POST:
            coll = category_collection
            rowid = 'category'
        existing = set(coll.addons.values_list('id', flat=True))
        requested = set(int(request.POST[k])
                        for k in sorted(request.POST.keys())
                        if k.endswith(rowid + '-webapp'))
        CollectionAddon.objects.filter(collection=coll,
            addon__in=(existing - requested)).delete()
        for id in requested - existing:
            CollectionAddon.objects.create(collection=coll, addon_id=id)
        messages.success(request, 'Changes successfully saved.')
        return redirect(reverse('admin.featured_apps'))

    return jingo.render(request, 'zadmin/featuredapp.html', {
        'home_featured': enumerate(home_collection.addons.all()),
        'category_featured': enumerate(category_collection.addons.all())
    })
Esempio n. 28
0
def edit(request):
    webapp = settings.APP_PREVIEW
    # Don't use request.amo_user since it has too much caching.
    amouser = UserProfile.objects.get(pk=request.user.id)
    if request.method == "POST":
        # ModelForm alters the instance you pass in.  We need to keep a copy
        # around in case we need to use it below (to email the user)
        original_email = amouser.email
        form = forms.UserEditForm(request.POST, request.FILES, request=request, instance=amouser, webapp=webapp)
        if form.is_valid():
            messages.success(request, _("Profile Updated"))
            if amouser.email != original_email:
                # Temporarily block email changes.
                if settings.APP_PREVIEW:
                    messages.error(request, "Error", "You cannot change your email on the " "developer preview site.")
                    return jingo.render(request, "users/edit.html", {"form": form, "amouser": amouser})

                l = {"user": amouser, "mail1": original_email, "mail2": amouser.email}
                log.info(u"User (%(user)s) has requested email change from" "(%(mail1)s) to (%(mail2)s)" % l)
                messages.info(
                    request,
                    _("Email Confirmation Sent"),
                    _(
                        u"An email has been sent to {0} to confirm your new "
                        "email address. For the change to take effect, you "
                        "need to click on the link provided in this email. "
                        "Until then, you can keep logging in with your "
                        "current email address."
                    ).format(amouser.email),
                )

                domain = settings.DOMAIN
                token, hash = EmailResetCode.create(amouser.id, amouser.email)
                url = "%s%s" % (settings.SITE_URL, reverse("users.emailchange", args=[amouser.id, token, hash]))
                t = loader.get_template("users/email/emailchange.ltxt")
                c = {"domain": domain, "url": url}
                send_mail(
                    _("Please confirm your email address " "change at %s" % domain),
                    t.render(Context(c)),
                    None,
                    [amouser.email],
                    use_blacklist=False,
                    real_email=True,
                )

                # Reset the original email back.  We aren't changing their
                # address until they confirm the new one
                amouser.email = original_email
            form.save()
            return redirect("users.edit")
        else:

            messages.error(
                request,
                _("Errors Found"),
                _("There were errors in the changes " "you made. Please correct them and " "resubmit."),
            )
    else:
        form = forms.UserEditForm(instance=amouser, webapp=webapp)
    return jingo.render(request, "users/edit.html", {"form": form, "amouser": amouser, "webapp": webapp})
Esempio n. 29
0
def version_edit(request, addon_id, addon, version_id):
    show_features = waffle.switch_is_active('buchets') and addon.is_packaged

    version = get_object_or_404(Version, pk=version_id, addon=addon)
    form = VersionForm(request.POST or None, instance=version)
    all_forms = [form]

    if show_features:
        appfeatures = version.features
        appfeatures_form = AppFeaturesForm(request.POST, instance=appfeatures)
        all_forms.append(appfeatures_form)

    if request.method == 'POST' and all(f.is_valid() for f in all_forms):
        [f.save() for f in all_forms]
        messages.success(request, _('Version successfully edited.'))
        return redirect(addon.get_dev_url('versions'))

    context = {
        'addon': addon,
        'version': version,
        'form': form
    }

    if show_features:
        context.update({
            'appfeatures_form': appfeatures_form,
            'appfeatures': appfeatures,
            'feature_list': [unicode(f) for f in appfeatures.to_list()]
        })

    return jingo.render(request, 'developers/apps/version_edit.html', context)
Esempio n. 30
0
def preload_submit(request, addon_id, addon, webapp):
    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).
            if test_plan.content_type == 'application/pdf':
                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 jingo.render(request, 'developers/apps/preload/submit.html', {
        'addon': addon,
        'form': form
    })
Esempio n. 31
0
def recalc_hash(request, file_id):

    file = get_object_or_404(File, pk=file_id)
    file.size = storage.size(file.file_path)
    file.hash = file.generate_hash()
    file.save()

    log.info('Recalculated hash for file ID %d' % file.id)
    messages.success(request,
                     'File hash and size recalculated for file %d.' % file.id)
    return {'success': 1}
Esempio n. 32
0
def submit_persona(request):
    if not waffle.flag_is_active(request, 'submit-personas'):
        return http.HttpResponseForbidden()
    form = NewPersonaForm(data=request.POST or None,
                          files=request.FILES or None, request=request)
    if request.method == 'POST' and form.is_valid():
        addon = form.save()
        messages.success(request, _('Persona successfully added.'))
        return redirect('personas.submit.done', addon.slug)
    return jingo.render(request, 'addons/impala/personas/submit.html',
                        dict(form=form))
Esempio n. 33
0
def blocklist(request, addon):
    """
    Blocklists the app by creating a new version/file.
    """
    if addon.status != amo.STATUS_BLOCKED:
        addon.create_blocklisted_version()
        messages.success(request, _('Created blocklisted version.'))
    else:
        messages.info(request, _('App already blocklisted.'))

    return redirect(addon.get_dev_url('versions'))
Esempio n. 34
0
def profile(request, addon_id, addon):
    profile_form = forms.ProfileForm(request.POST or None, instance=addon)

    if request.method == 'POST' and profile_form.is_valid():
        profile_form.save()
        amo.log(amo.LOG.EDIT_PROPERTIES, addon)
        messages.success(request, _('Changes successfully saved.'))
        return redirect('devhub.addons.profile', addon.slug)

    return jingo.render(request, 'devhub/addons/profile.html',
                        dict(addon=addon, profile_form=profile_form))
Esempio n. 35
0
def fix_disabled_file(request):
    file_ = None
    if request.method == 'POST' and 'file' in request.POST:
        file_ = get_object_or_404(File, id=request.POST['file'])
        if 'confirm' in request.POST:
            file_.unhide_disabled_file()
            messages.success(request, 'We have done a great thing.')
            return redirect('zadmin.fix-disabled')
    return jingo.render(request, 'zadmin/fix-disabled.html',
                        {'file': file_,
                         'file_id': request.POST.get('file', '')})
Esempio n. 36
0
def terms(request):
    form = forms.DevAgreementForm({'read_dev_agreement': True},
                                  instance=request.amo_user)
    if request.POST and form.is_valid():
        form.save()
        log.info('Dev agreement agreed for user: %s' % request.amo_user.pk)
        messages.success(request, _('Terms of service accepted.'))
    return jingo.render(request, 'developers/terms.html', {
        'accepted': request.amo_user.read_dev_agreement,
        'agreement_form': form
    })
Esempio n. 37
0
def admin_edit(request, user):
    if request.method == 'POST':
        form = forms.AdminUserEditForm(request.POST, request.FILES,
                                       request=request, instance=user)
        if form.is_valid():
            form.save()
            messages.success(request, _('Profile Updated'))
            return http.HttpResponseRedirect(reverse('zadmin.index'))
    else:
        form = forms.AdminUserEditForm(instance=user, request=request)
    return render(request, 'users/edit.html', {'form': form, 'amouser': user})
Esempio n. 38
0
def report_abuse(request, user):
    form = AbuseForm(request.POST or None, request=request)
    if request.method == 'POST' and form.is_valid():
        send_abuse_report(request, user, form.cleaned_data['text'])
        messages.success(request, _('User reported.'))
    else:
        return jingo.render(request, 'users/report_abuse_full.html', {
            'profile': user,
            'abuse_form': form,
        })
    return redirect(user.get_url_path())
Esempio n. 39
0
def edit(request):
    # Don't use request.user since it has too much caching.
    amouser = UserProfile.objects.get(pk=request.user.id)
    if request.method == 'POST':
        # ModelForm alters the instance you pass in.  We need to keep a copy
        # around in case we need to use it below (to email the user)
        original_email = amouser.email
        form = forms.UserEditForm(request.POST, request.FILES, request=request,
                                  instance=amouser)
        if form.is_valid():
            messages.success(request, _('Profile Updated'))
            if amouser.email != original_email:

                l = {'user': amouser,
                     'mail1': original_email,
                     'mail2': amouser.email}
                log.info(u"User (%(user)s) has requested email change from "
                         u"(%(mail1)s) to (%(mail2)s)" % l)
                messages.info(
                    request, _('Email Confirmation Sent'),
                    _(u'An email has been sent to {0} to confirm your new '
                      u'email address. For the change to take effect, you '
                      u'need to click on the link provided in this email. '
                      u'Until then, you can keep logging in with your '
                      u'current email address.').format(amouser.email))

                token, hash_ = EmailResetCode.create(amouser.id, amouser.email)
                url = '%s%s' % (settings.SITE_URL,
                                reverse('users.emailchange',
                                        args=[amouser.id, token, hash_]))
                t = loader.get_template('users/email/emailchange.ltxt')
                c = {'domain': settings.DOMAIN, 'url': url}
                send_mail(
                    _('Please confirm your email address '
                      'change at %s' % settings.DOMAIN),
                    t.render(Context(c)), None, [amouser.email],
                    use_blacklist=False, real_email=True)

                # Reset the original email back.  We aren't changing their
                # address until they confirm the new one
                amouser.email = original_email
            form.save()
            return redirect('users.edit')
        else:

            messages.error(
                request,
                _('Errors Found'),
                _('There were errors in the changes you made. Please correct '
                  'them and resubmit.'))
    else:
        form = forms.UserEditForm(instance=amouser, request=request)
    return render(request, 'users/edit.html',
                  {'form': form, 'amouser': amouser})
Esempio n. 40
0
def report_abuse(request, addon):
    form = AbuseForm(request.POST or None, request=request)
    if request.method == "POST" and form.is_valid():
        send_abuse_report(request, addon, form.cleaned_data['text'])
        messages.success(request, _('Abuse reported.'))
        return http.HttpResponseRedirect(addon.get_url_path())
    else:
        return render(request, 'addons/report_abuse_full.html', {
            'addon': addon,
            'abuse_form': form
        })
Esempio n. 41
0
def edit(request, collection, username, slug):
    is_admin = acl.action_allowed(request, 'Admin', '%')

    if request.method == 'POST':
        initial = initial_data_from_request(request)
        if collection.author_id:  # Don't try to change the author.
            initial['author'] = collection.author
        form = forms.CollectionForm(request.POST,
                                    request.FILES,
                                    initial=initial,
                                    instance=collection)
        if form.is_valid():
            collection = form.save()
            title = _("Collection updated!")
            msg = _(("""<a href="%(url)s">View your collection</a> to see the
                        changes.""")) % {
                'url': collection.get_url_path()
            }
            messages.success(request,
                             title,
                             msg,
                             extra_tags='collection',
                             message_safe=True)
            log.info(u'%s edited collection %s' %
                     (request.amo_user, collection.id))
            return http.HttpResponseRedirect(collection.edit_url())
    else:
        form = forms.CollectionForm(instance=collection)

    qs = (CollectionAddon.uncached.using('default').filter(
        collection=collection))
    meta = dict((c.addon_id, c) for c in qs)
    addons = collection.addons.no_cache().all()
    comments = get_notes(collection, raw=True).next()

    if is_admin:
        initial = dict(type=collection.type,
                       application=collection.application_id)
        admin_form = forms.AdminForm(initial=initial)
    else:
        admin_form = None

    data = dict(collection=collection,
                form=form,
                user=request.amo_user,
                username=username,
                slug=slug,
                meta=meta,
                filter=get_filter(request),
                is_admin=is_admin,
                admin_form=admin_form,
                addons=addons,
                comments=comments)
    return render(request, 'bandwagon/edit.html', data)
Esempio n. 42
0
def memcache(request):
    form = YesImSure(request.POST or None)
    if form.is_valid():
        cache.clear()
        form = YesImSure()
        messages.success(request, 'Cache cleared')
    if cache._cache and hasattr(cache._cache, 'get_stats'):
        stats = cache._cache.get_stats()
    else:
        stats = []
    return jingo.render(request, 'zadmin/memcache.html',
                        {'form': form, 'stats': stats})
Esempio n. 43
0
def report_abuse(request, user_id):
    user = get_object_or_404(UserProfile, pk=user_id)
    form = AbuseForm(request.POST or None, request=request)
    if request.method == "POST" and form.is_valid():
        send_abuse_report(request, user, form.cleaned_data['text'])
        messages.success(request, _('User reported.'))
    else:
        return jingo.render(request, 'users/report_abuse_full.html', {
            'profile': user,
            'abuse_form': form,
        })
    return redirect(reverse('users.profile', args=[user.pk]))
Esempio n. 44
0
def profile(request, addon_id, addon, webapp=False):
    profile_form = forms.ProfileForm(request.POST or None, instance=addon)

    if request.method == 'POST' and profile_form.is_valid():
        profile_form.save()
        amo.log(amo.LOG.EDIT_PROPERTIES, addon)
        messages.success(request, _('Changes successfully saved.'))
        return redirect(addon.get_dev_url('profile'))

    return jingo.render(
        request, 'developers/apps/profile.html',
        dict(addon=addon, webapp=webapp, profile_form=profile_form))
Esempio n. 45
0
def delete_photo(request):
    u = request.amo_user

    if request.method == 'POST':
        u.picture_type = ''
        u.save()
        log.debug(u"User (%s) deleted photo" % u)
        tasks.delete_photo.delay(u.picture_path)
        messages.success(request, _('Photo Deleted'))
        return http.HttpResponseRedirect(
            reverse('users.edit') + '#user-profile')

    return render(request, 'users/delete_photo.html', dict(user=u))
Esempio n. 46
0
def delete_icon(request, collection, username, slug):
    log.debug(u"User deleted collection (%s) icon " % slug)
    tasks.delete_icon(
        os.path.join(collection.get_img_dir(), '%d.png' % collection.id))

    collection.icontype = ''
    collection.save()

    if request.is_ajax():
        return {'icon': collection.icon_url}
    else:
        messages.success(request, _('Icon Deleted'))
        return redirect(collection.edit_url())
Esempio n. 47
0
def confirm(request, user, token):
    if not user.confirmationcode:
        return redirect('users.login')

    if user.confirmationcode != token:
        log.info(u"Account confirmation failed for user (%s)", user)
        messages.error(request, _('Invalid confirmation code!'))
        return redirect('users.login')

    user.confirmationcode = ''
    user.save()
    messages.success(request, _('Successfully verified!'))
    log.info(u"Account confirmed for user (%s)", user)
    return redirect('users.login')
Esempio n. 48
0
def refund_reason(request, contribution, wizard):
    addon = contribution.addon
    if not 'request' in wizard.get_progress():
        return redirect('users.support', contribution.pk, 'request')
    if contribution.transaction_id is None:
        messages.error(
            request,
            _('A refund cannot be applied for yet. Please try again'
              ' later. If this error persists contact '
              '[email protected].'))
        paypal_log.info('Refund requested for contribution with no '
                        'transaction_id: %r' % (contribution.pk, ))
        return redirect('users.purchases')

    if contribution.is_instant_refund():
        paypal.refund(contribution.paykey)
        # TODO: Consider requiring a refund reason for instant refunds.
        refund = contribution.enqueue_refund(amo.REFUND_APPROVED_INSTANT)
        paypal_log.info('Refund %r issued for contribution %r' %
                        (refund.pk, contribution.pk))
        # Note: we have to wait for PayPal to issue an IPN before it's
        # completely refunded.
        messages.success(request, _('Refund is being processed.'))
        return redirect('users.purchases')

    form = forms.ContactForm(request.POST or None)
    if request.method == 'POST' and form.is_valid():
        reason = form.cleaned_data['text']
        template = jingo.render_to_string(
            request,
            wizard.tpl('emails/refund-request.txt'),
            context={
                'addon': addon,
                'form': form,
                'user': request.amo_user,
                'contribution': contribution,
                'refund_url': contribution.get_absolute_refund_url(),
                'refund_reason': reason
            })
        log.info('Refund request sent by user: %s for addon: %s' %
                 (request.amo_user.pk, addon.pk))
        # L10n: %s is the addon name.
        send_mail(_(u'New Refund Request for %s' % addon.name), template,
                  settings.NOBODY_EMAIL, [smart_str(addon.support_email)])
        # Add this refund request to the queue.
        contribution.enqueue_refund(amo.REFUND_PENDING, reason)
        return redirect(
            reverse('users.support', args=[contribution.pk, 'refund-sent']))

    return wizard.render(request, wizard.tpl('refund.html'), {'form': form})
Esempio n. 49
0
def collection_message(request, collection, option):
    if option == 'add':
        title = _('Collection created!')
        msg = _("""Your new collection is shown below. You can <a
                   href="%(url)s">edit additional settings</a> if you'd
                   like.""") % {'url': collection.edit_url()}
    elif option == 'update':
        title = _('Collection updated!')
        msg = _("""<a href="%(url)s">View your collection</a> to see the
                   changes.""") % {'url': collection.get_url_path()}
    else:
        raise ValueError('Incorrect option "%s", '
                         'takes only "add" or "update".' % option)
    messages.success(request, title, msg, message_safe=True)
Esempio n. 50
0
def version_edit(request, addon_id, addon, version_id):
    version = get_object_or_404(Version, pk=version_id, addon=addon)
    form = VersionForm(request.POST or None, instance=version)

    if request.method == 'POST' and form.is_valid():
        form.save()
        messages.success(request, _('Version successfully edited.'))
        return redirect(addon.get_dev_url('versions'))

    return jingo.render(request, 'developers/apps/version_edit.html', {
        'addon': addon,
        'version': version,
        'form': form
    })
Esempio n. 51
0
def email_devs(request):
    form = DevMailerForm(request.POST or None)
    preview = EmailPreviewTopic(topic='email-devs')
    if preview.filter().count():
        preview_csv = reverse('zadmin.email_preview_csv', args=[preview.topic])
    else:
        preview_csv = None
    if request.method == 'POST' and form.is_valid():
        data = form.cleaned_data
        listed = amo.LISTED_STATUSES
        qs = (AddonUser.objects.filter(
            role__in=(amo.AUTHOR_ROLE_DEV, amo.AUTHOR_ROLE_OWNER),
            addon__status__in=listed).exclude(user__email=None))
        if data['recipients'] == 'eula':
            qs = qs.exclude(addon__eula=None)
        elif data['recipients'] == 'payments':
            qs = qs.filter(addon__type=amo.ADDON_WEBAPP)
            qs = qs.exclude(addon__paypal_id=None)
            qs = qs.exclude(addon__premium_type__in=(amo.ADDON_FREE,
                                                     amo.ADDON_OTHER_INAPP))
        elif data['recipients'] == 'apps':
            qs = qs.filter(addon__type=amo.ADDON_WEBAPP)
        elif data['recipients'] == 'desktop_apps':
            qs = (qs.filter(
                addon__type=amo.ADDON_WEBAPP,
                addon__addondevicetype__device_type=amo.DEVICE_DESKTOP.id))
        elif data['recipients'] == 'sdk':
            qs = qs.exclude(addon__versions__files__jetpack_version=None)
        else:
            raise NotImplementedError('If you want to support emailing other '
                                      'types of developers, do it here!')
        if data['preview_only']:
            # Clear out the last batch of previewed emails.
            preview.filter().delete()
        total = 0
        for emails in chunked(set(qs.values_list('user__email', flat=True)),
                              100):
            total += len(emails)
            tasks.admin_email.delay(emails,
                                    data['subject'],
                                    data['message'],
                                    preview_only=data['preview_only'],
                                    preview_topic=preview.topic)
        msg = 'Emails queued for delivery: %s' % total
        if data['preview_only']:
            msg = '%s (for preview only, emails not sent!)' % msg
        messages.success(request, msg)
        return redirect('zadmin.email_devs')
    return jingo.render(request, 'zadmin/email-devs.html',
                        dict(form=form, preview_csv=preview_csv))
Esempio n. 52
0
def notify_failure(request, job):
    job = get_object_or_404(ValidationJob, pk=job)
    notify_form = NotifyForm(request.POST, text='failure')

    if not notify_form.is_valid():
        messages.error(request, notify_form)

    else:
        file_pks = job.result_failing().values_list('file_id', flat=True)
        for chunk in chunked(file_pks, 100):
            tasks.notify_failed.delay(chunk, job.pk, notify_form.cleaned_data)
        messages.success(request, _('Notifying authors task started.'))

    return redirect(reverse('zadmin.validation'))
Esempio n. 53
0
def recalc_hash(request, file_id):

    file = get_object_or_404(File, pk=file_id)
    file.size = int(max(1, round(os.path.getsize(file.file_path) / 1024, 0)))
    file.hash = file.generate_hash()
    file.save()

    log.info('Recalculated hash for file ID %d' % file.id)
    messages.success(request,
                     'File hash and size recalculated for file %d.' % file.id)

    redirect_url = reverse('zadmin.addon_manage',
                           args=[file.version.addon.slug])
    page = request.GET.get('page', 1)
    return redirect(urlparams(redirect_url, page=page))
Esempio n. 54
0
def notify_success(request, job):
    job = get_object_or_404(ValidationJob, pk=job)
    notify_form = NotifyForm(request.POST, text='success')

    if not notify_form.is_valid():
        messages.error(request, notify_form.errors)

    else:
        versions = completed_versions_dirty(job)
        for chunk in chunked(versions, 100):
            tasks.notify_success.delay(chunk, job.pk, notify_form.cleaned_data)
        messages.success(request, _('Updating max version task and '
                                    'notifying authors started.'))

    return redirect(reverse('zadmin.validation'))
Esempio n. 55
0
def delete(request):
    amouser = request.user
    if request.method == 'POST':
        form = forms.UserDeleteForm(request.POST, request=request)
        if form.is_valid():
            messages.success(request, _('Profile Deleted'))
            amouser.anonymize()
            logout(request)
            form = None
            return http.HttpResponseRedirect(reverse('users.login'))
    else:
        form = forms.UserDeleteForm()

    return render(request, 'users/delete.html',
                  {'form': form, 'amouser': amouser})
Esempio n. 56
0
def report_abuse(request, addon):
    if not settings.REPORT_ABUSE:
        raise http.Http404()

    form = AbuseForm(request.POST or None, request=request)
    if request.method == "POST" and form.is_valid():
        url = reverse('addons.detail', args=[addon.slug])
        send_abuse_report(request, addon, url, form.cleaned_data['text'])
        messages.success(request, _('Abuse reported.'))
        return redirect('addons.detail', addon.slug)
    else:
        return jingo.render(request, 'addons/report_abuse_full.html', {
            'addon': addon,
            'abuse_form': form,
        })
Esempio n. 57
0
def content_ratings(request, addon_id, addon):
    if not addon.is_rated():
        return redirect(addon.get_dev_url('ratings_edit'))

    # Use _ratings_success_msg to display success message.
    session = request.session
    if 'ratings_edit' in session and addon.id in session['ratings_edit']:
        prev_state = session['ratings_edit'][addon.id]
        msg = _ratings_success_msg(addon, prev_state['app_status'],
                                   prev_state['rating_modified'])
        messages.success(request, msg) if msg else None
        del session['ratings_edit'][addon.id]  # Clear msg so not shown again.
        request.session.modified = True

    return render(request, 'developers/apps/ratings/ratings_summary.html',
                  {'addon': addon})
Esempio n. 58
0
def confirm(request, user_id, token):
    user = get_object_or_404(UserProfile, id=user_id)

    if not user.confirmationcode:
        return http.HttpResponseRedirect(reverse('users.login'))

    if user.confirmationcode != token:
        log.info(u"Account confirmation failed for user (%s)", user)
        messages.error(request, _('Invalid confirmation code!'))
        return http.HttpResponseRedirect(reverse('users.login'))

    user.confirmationcode = ''
    user.save()
    messages.success(request, _('Successfully verified!'))
    log.info(u"Account confirmed for user (%s)", user)
    return http.HttpResponseRedirect(reverse('users.login'))
Esempio n. 59
0
def status(request, addon_id, addon, webapp=False):
    form = forms.AppAppealForm(request.POST, product=addon)
    upload_form = NewWebappVersionForm(request.POST or None,
                                       is_packaged=True,
                                       addon=addon,
                                       request=request)

    if request.method == 'POST':
        if 'resubmit-app' in request.POST and form.is_valid():
            form.save()
            messages.success(request, _('App successfully resubmitted.'))
            return redirect(addon.get_dev_url('versions'))

        elif 'upload-version' in request.POST and upload_form.is_valid():
            ver = Version.from_upload(upload_form.cleaned_data['upload'],
                                      addon, [amo.PLATFORM_ALL])
            messages.success(request, _('New version successfully added.'))
            log.info('[Webapp:%s] New version created id=%s from upload: %s' %
                     (addon, ver.pk, upload_form.cleaned_data['upload']))
            return redirect(addon.get_dev_url('versions.edit', args=[ver.pk]))

    ctx = {
        'addon': addon,
        'webapp': webapp,
        'form': form,
        'upload_form': upload_form
    }

    # Used in the delete version modal.
    if addon.is_packaged:
        versions = addon.versions.values('id', 'version')
        version_strings = dict((v['id'], v) for v in versions)
        version_strings['num'] = len(versions)
        ctx['version_strings'] = json.dumps(version_strings)

    if addon.status == amo.STATUS_REJECTED:
        try:
            entry = (AppLog.objects.filter(
                addon=addon,
                activity_log__action=amo.LOG.REJECT_VERSION.id).order_by(
                    '-created'))[0]
        except IndexError:
            entry = None
        # This contains the rejection reason and timestamp.
        ctx['rejection'] = entry and entry.activity_log

    return jingo.render(request, 'developers/apps/status.html', ctx)
Esempio n. 60
0
def edit_contributors(request, collection, username, slug):
    is_admin = acl.action_allowed(request, 'Admin', '%')

    if is_admin:
        admin_form = forms.AdminForm(request.POST)
        if admin_form.is_valid():
            admin_form.save(collection)

    form = forms.ContributorsForm(request.POST)

    if form.is_valid():
        form.save(collection)
        messages.success(request, _('Your collection has been updated.'))
        if form.cleaned_data['new_owner']:
            return http.HttpResponseRedirect(collection.get_url_path())

    return http.HttpResponseRedirect(collection.edit_url() + '#users-edit')