def library_autocomplete(request): """ 'Live' search by name """ from search.helpers import package_query from elasticutils import F q = request.GET.get('q') limit = request.GET.get('limit') try: limit = int(limit) except: limit = settings.LIBRARY_AUTOCOMPLETE_LIMIT ids = (settings.MINIMUM_PACKAGE_ID, settings.MINIMUM_PACKAGE_ID - 1) notAddonKit = ~(F(id_number=ids[0]) | F(id_number=ids[1])) onlyMyPrivateLibs = (F(active=True) | F(author=request.user.id)) try: qs = (Package.search().query(or_=package_query(q)).filter(type='l') .filter(notAddonKit).filter(onlyMyPrivateLibs)) found = qs[:limit] except Exception, ex: log.exception('Library autocomplete error') found = []
def one_newsletter_signup(request, template_name): success = False # not in a footer, but we use the same form form = NewsletterFooterForm(request.locale, request.POST or None) if form.is_valid(): data = form.cleaned_data request.newsletter_lang = data.get('lang', 'en') or 'en' kwargs = { 'format': data['fmt'], } # add optional data kwargs.update(dict((k, data[k]) for k in ['country', 'lang', 'source_url'] if data[k])) try: basket.subscribe(data['email'], data['newsletter'], **kwargs) except basket.BasketException: log.exception("Error subscribing %s to newsletter %s" % (data['email'], data['newsletter'])) form.errors['__all__'] = form.error_class([general_error]) else: success = True request.newsletter_form = form request.newsletter_success = success return l10n_utils.render(request, template_name, {})
def process_pay_req(request): form = VerifyForm(request.GET) if not form.is_valid(): return _error(request, msg=form.errors.as_text(), is_simulation=form.is_simulation) if settings.ONLY_SIMULATIONS and not form.is_simulation: # Real payments are currently disabled. # Only simulated payments are allowed. return render(request, 'error.html', {'error': _('Payments are temporarily disabled.')}, status=503) try: pay_req = verify_jwt( form.cleaned_data['req'], settings.DOMAIN, # JWT audience. form.secret, required_keys=('request.id', 'request.pricePoint', # A price tier we'll lookup. 'request.name', 'request.description', 'request.postbackURL', 'request.chargebackURL')) except (TypeError, InvalidJWT, RequestExpired), exc: log.exception('calling verify_jwt') return _error(request, exception=exc, is_simulation=form.is_simulation)
def wrapper(request, *args, **kw): raw_sig_request = request.GET.get('r') or request.POST.get('r') if not raw_sig_request: return http.HttpResponseBadRequest('r was not in request') raw_sig_request = str(raw_sig_request) allowed = False try: sig_request = jwt.decode(raw_sig_request, verify=False) except jwt.DecodeError: log.exception('signed request was invalid') else: user_email = sig_request['iss'] em = get_object_or_404(VerifiedEmail, email=user_email) if em.upload_key: try: jwt.decode(raw_sig_request, em.upload_key, verify=True) allowed = True except jwt.DecodeError: log.exception('signed request for %s was invalid' % user_email) else: log.info('no upload_key for %s' % user_email) if not allowed: return http.HttpResponseForbidden() return view(request, raw_sig_request, sig_request, *args, **kw)
def confirm(request, token): """ Confirm subscriptions. """ success = generic_error = token_error = False try: result = basket.confirm(token) except basket.BasketException as e: log.exception("Exception confirming token %s" % token) if e.code == basket.errors.BASKET_UNKNOWN_TOKEN: token_error = True else: # Any other exception generic_error = True else: if result['status'] == 'ok': success = True else: # Shouldn't happen (errors should raise exception), # but just in case: generic_error = True return l10n_utils.render( request, 'newsletter/confirm.html', {'success': success, 'generic_error': generic_error, 'token_error': token_error})
def newsletter_subscribe(request): if request.method == 'POST': newsletters = request.POST.get('newsletters', None) form = NewsletterFooterForm(newsletters, l10n_utils.get_locale(request), request.POST) errors = [] if form.is_valid(): data = form.cleaned_data kwargs = {'format': data['fmt']} # add optional data kwargs.update(dict((k, data[k]) for k in ['country', 'lang', 'source_url', 'first_name', 'last_name', ] if data[k])) try: basket.subscribe(data['email'], data['newsletters'], **kwargs) except basket.BasketException as e: if e.code == basket.errors.BASKET_INVALID_EMAIL: errors.append(unicode(invalid_email_address)) else: log.exception("Error subscribing %s to newsletter %s" % (data['email'], data['newsletters'])) errors.append(unicode(general_error)) else: if 'email' in form.errors: errors.append(_('Please enter a valid email address')) if 'privacy' in form.errors: errors.append(_('You must agree to the privacy notice')) for fieldname in ('fmt', 'lang', 'country'): if fieldname in form.errors: errors.extend(form.errors[fieldname]) # form error messages may contain unsanitized user input errors = map(escape, errors) if request.is_ajax(): # return JSON if errors: resp = { 'success': False, 'errors': errors, } else: resp = {'success': True} return HttpResponseJSON(resp) else: ctx = {'newsletter_form': form} if not errors: ctx['success'] = True return l10n_utils.render(request, 'newsletter/mozilla-and-you.html', ctx) return l10n_utils.render(request, 'newsletter/mozilla-and-you.html')
def unwrap_signed_request(request): """ Decodes and returns Facebook's `signed_request` data. See https://developers.facebook.com/docs/howtos/login/signed-request/ """ try: encoded_signed_request = request.REQUEST['signed_request'] except KeyError: log.exception('signed_request not set') return {} encoded_string_data = encoded_signed_request.partition('.')[2] # Pad with `=` to make string length a multiple of 4 # and thus prevent a base64 error padding = ''.ljust(4 - len(encoded_string_data) % 4, '=') padded_string = ''.join([encoded_string_data, padding]) # Convert to byte data for base64 encoded_byte_data = bytes(padded_string) signed_request = json.loads(urlsafe_b64decode(encoded_byte_data)) # Change Facebook locale's underscore to hyphen # ex. `en_US` to `en-US` try: locale = signed_request['user']['locale'] except KeyError: locale = None if locale: signed_request['user']['locale'] = locale.replace('_', '-') return signed_request
def page(name, tmpl, decorators=None, **kwargs): """ Define a bedrock page. The URL name is the template name, with the extension stripped and the slashes changed to dots. So if tmpl="path/to/template.html", then the page's URL name will be "path.to.template". @param name: The URL regex pattern. If not empty, a trailing slash is added automatically, so it shouldn't be included in the parameter value. @param tmpl: The template name. Also used to come up with the URL name. @param decorators: A decorator or an iterable of decorators that should be applied to the view. @param kwargs: Any additional arguments are passed to l10n_utils.render after the request and the template name. """ pattern = r'^%s/$' % name if name else r'^$' # Set the name of the view to the template path replaced with dots (base, ext) = os.path.splitext(tmpl) view_name = base.replace('/', '.') # we don't have a caching backend yet, so no csrf (it's just a # newsletter form anyway) @csrf_exempt def _view(request): if newrelic: # Name this in New Relic to differentiate pages newrelic.agent.set_transaction_name( 'mozorg.util.page:' + view_name.replace('.', '_')) kwargs.setdefault('urlname', view_name) # skip l10n if path exempt name_prefix = request.path_info.split('/', 2)[1] if name_prefix in settings.SUPPORTED_NONLOCALES: return django_render(request, tmpl, kwargs) return l10n_utils.render(request, tmpl, kwargs) # This is for graphite so that we can differentiate pages _view.page_name = view_name # Apply decorators if decorators: if callable(decorators): _view = decorators(_view) else: try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=view_name)
def wrapper(request, *args, **kw): signed_req = request.GET.get('req') or request.POST.get('req') if not signed_req: return http.HttpResponseBadRequest() try: req = verify_request(signed_req) except InappPaymentError, exc: etype, val, tb = sys.exc_info() exc_class = etype.__name__ InappPayLog.log(request, 'EXCEPTION', app_public_key=exc.app_id, exc_class=exc_class) log.exception('in @require_inapp_request') return render_error(request, exc, exc_class=exc_class)
def album_art(track_id, **kw): tr = Track.objects.get(pk=track_id) try: fm = pylast.get_lastfm_network(api_key=settings.LAST_FM_KEY) alb = fm.get_album(tr.artist, tr.album) (Track.objects.filter(pk=track_id) .update(large_art_url=alb.get_cover_image(pylast.COVER_LARGE), medium_art_url=alb.get_cover_image(pylast.COVER_MEDIUM), small_art_url=alb.get_cover_image(pylast.COVER_SMALL))) except pylast.WSError: # Probably album not found log.exception('in album_art') print 'got artwork for %s' % tr
def transaction_refund(request, uuid): contrib = get_object_or_404(Contribution, uuid=uuid, type=amo.CONTRIB_PURCHASE) if contrib.has_refund(): messages.error(request, _('A refund has already been processed.')) return redirect(reverse('lookup.transaction_summary', args=[uuid])) form = TransactionRefundForm(request.POST) if not form.is_valid(): messages.error(request, str(form.errors)) return redirect(reverse('lookup.transaction_summary', args=[uuid])) try: res = client.api.bango.refund.post({'uuid': contrib.transaction_id}) except (HttpClientError, HttpServerError): # Either doing something not supposed to or Solitude had an issue. log.exception('Refund error: %s' % uuid) messages.error( request, _('You cannot make a refund request for this transaction.')) return redirect(reverse('lookup.transaction_summary', args=[uuid])) if res['status'] == STATUS_PENDING: # Create pending Refund. contrib.enqueue_refund( status=amo.REFUND_PENDING, refund_reason=form.cleaned_data['refund_reason'], user=request.amo_user) log.info('Refund pending: %s' % uuid) email_buyer_refund_pending(contrib) messages.success( request, _('Refund for this transaction now pending.')) elif res['status'] == STATUS_COMPLETED: # Create approved Refund. contrib.enqueue_refund( status=amo.REFUND_APPROVED, refund_reason=form.cleaned_data['refund_reason'], user=request.amo_user) log.info('Refund approved: %s' % uuid) email_buyer_refund_approved(contrib) messages.success( request, _('Refund for this transaction successfully approved.')) elif res['status'] == STATUS_FAILED: # Bango no like. log.error('Refund failed: %s' % uuid) messages.error( request, _('Refund request for this transaction failed.')) return redirect(reverse('lookup.transaction_summary', args=[uuid]))
def _change_trans_state(request, data, state): try: moz_trans_id = data['response']['transactionID'] # e.g. transaction_id=1234 pd = urlparse.parse_qs(data['request']['productData']) trans = Transaction.objects.get(pk=pd['transaction_id'][0]) trans.moz_transaction_id = moz_trans_id log.info('transaction %s changed from state %s to %s' % (trans.pk, trans.state, state)) trans.state = state trans.save() except: log.exception('Exception while processing request from %s' % request.META.get('REMOTE_ADDR')) raise
def process_pay_req(request): form = VerifyForm(request.GET) if not form.is_valid(): return _error(request, msg=form.errors.as_text()) try: pay_req = verify_jwt( form.cleaned_data['req'], settings.DOMAIN, # JWT audience. form.secret, required_keys=('request.id', 'request.pricePoint', # A price tier we'll lookup. 'request.name', 'request.description')) except (TypeError, InvalidJWT, RequestExpired), exc: log.exception('calling verify_jwt') return _error(request, exception=exc)
def recovery(request): """ Let user enter their email address and be sent a message with a link to manage their subscriptions. """ if request.method == 'POST': form = EmailForm(request.POST) if form.is_valid(): email = form.cleaned_data['email'] try: # Try it - basket will return an error if the email is unknown basket.send_recovery_message(email) except basket.BasketException as e: # Was it that their email was not known? Or it could be invalid, # but that doesn't really make a difference. if e.code in (basket.errors.BASKET_UNKNOWN_EMAIL, basket.errors.BASKET_INVALID_EMAIL): # Tell them, give them a link to go subscribe if they want url = reverse('newsletter.subscribe') form.errors['email'] = \ form.error_class([unknown_address_text % url]) else: # Log the details log.exception("Error sending recovery message") # and tell the user that something went wrong form.errors['__all__'] = form.error_class([general_error]) else: messages.add_message(request, messages.INFO, recovery_text) # Redir as GET, signalling success return redirect(request.path + "?success") elif 'success' in request.GET: # We were redirected after a successful submission. # A message will be displayed; don't display the form again. form = None else: form = EmailForm() # This view is shared between two different templates. For context see bug 1442129. if '/newsletter/opt-out-confirmation/' in request.get_full_path(): template = "newsletter/opt-out-confirmation.html" else: template = "newsletter/recovery.html" return l10n_utils.render(request, template, {'form': form})
def lobby(request): form = VerifyForm(request.GET) if not form.is_valid(): return _error(request, msg=form.errors.as_text()) pin_form = VerifyPinForm() try: pay_req = verify_jwt( form.cleaned_data['req'], settings.DOMAIN, # JWT audience. form.secret, required_keys=('request.price', # An array of # price/currency 'request.name', 'request.description')) except (TypeError, InvalidJWT, RequestExpired), exc: log.exception('calling verify_jwt') return _error(request, exception=exc)
def recovery(request): """ Let user enter their email address and be sent a message with a link to manage their subscriptions. """ if request.method == 'POST': form = EmailForm(request.POST) if form.is_valid(): email = form.cleaned_data['email'] try: # Try it - basket will return an error if the email is unknown basket.send_recovery_message(email) except basket.BasketException as e: # Was it that their email was not known? Or it could be invalid, # but that doesn't really make a difference. if e.code in (basket.errors.BASKET_UNKNOWN_EMAIL, basket.errors.BASKET_INVALID_EMAIL): # Tell them, give them a link to go subscribe if they want url = reverse('newsletter.subscribe') form.errors['email'] = \ form.error_class([unknown_address_text % url]) else: # Log the details log.exception("Error sending recovery message") # and tell the user that something went wrong form.errors['__all__'] = form.error_class([general_error]) else: messages.add_message(request, messages.INFO, recovery_text) # Redir as GET, signalling success return redirect(request.path + "?success") elif 'success' in request.GET: # We were redirected after a successful submission. # A message will be displayed; don't display the form again. form = None else: form = EmailForm() return l10n_utils.render( request, "newsletter/recovery.html", { 'form': form, })
def confirm(request, token): """ Confirm subscriptions. """ success = generic_error = token_error = rate_limit_error = False try: result = basket.confirm(token) except basket.BasketException as e: log.exception("Exception confirming token %s" % token) if e.code == basket.errors.BASKET_UNKNOWN_TOKEN: token_error = True elif e.code == basket.errors.BASKET_USAGE_ERROR: rate_limit_error = True else: # Any other exception generic_error = True else: if result['status'] == 'ok': success = True else: # Shouldn't happen (errors should raise exception), # but just in case: generic_error = True # Assume rate limit error means user already confirmed and clicked confirm # link twice in quick succession if success or rate_limit_error: qparams = ['confirm=1'] qs = request.META.get('QUERY_STRING', '') if qs: qparams.append(qs) return HttpResponseRedirect( "%s?%s" % (reverse('newsletter.existing.token', kwargs={'token': token}), '&'.join(qparams))) else: return l10n_utils.render(request, 'newsletter/confirm.html', { 'success': success, 'generic_error': generic_error, 'token_error': token_error }, ftl_files=FTL_FILES)
def confirm(request, token): """ Confirm subscriptions. """ success = generic_error = token_error = rate_limit_error = False try: result = basket.confirm(token) except basket.BasketException as e: log.exception(f"Exception confirming token {token}") if e.code == basket.errors.BASKET_UNKNOWN_TOKEN: token_error = True elif e.code == basket.errors.BASKET_USAGE_ERROR: rate_limit_error = True else: # Any other exception generic_error = True else: if result["status"] == "ok": success = True else: # Shouldn't happen (errors should raise exception), # but just in case: generic_error = True # Assume rate limit error means user already confirmed and clicked confirm # link twice in quick succession if success or rate_limit_error: qparams = ["confirm=1"] qs = request.META.get("QUERY_STRING", "") if qs: qparams.append(qs) return HttpResponseRedirect("{}?{}".format( reverse("newsletter.existing.token", kwargs={"token": token}), "&".join(qparams))) else: return l10n_utils.render(request, "newsletter/confirm.html", { "success": success, "generic_error": generic_error, "token_error": token_error }, ftl_files=FTL_FILES)
def confirm(request, token): """ Confirm subscriptions. """ success = generic_error = token_error = rate_limit_error = False try: result = basket.confirm(token) except basket.BasketException as e: log.exception("Exception confirming token %s" % token) if e.code == basket.errors.BASKET_UNKNOWN_TOKEN: token_error = True elif e.code == basket.errors.BASKET_USAGE_ERROR: rate_limit_error = True else: # Any other exception generic_error = True else: if result['status'] == 'ok': success = True else: # Shouldn't happen (errors should raise exception), # but just in case: generic_error = True # Assume rate limit error means user already confirmed and clicked confirm # link twice in quick succession if success or rate_limit_error: qparams = ['confirm=1'] qs = request.META.get('QUERY_STRING', '') if qs: qparams.append(qs) return HttpResponseRedirect("%s?%s" % (reverse('newsletter.existing.token', kwargs={'token': token}), '&'.join(qparams))) else: return l10n_utils.render( request, 'newsletter/confirm.html', {'success': success, 'generic_error': generic_error, 'token_error': token_error})
def recovery(request): """ Let user enter their email address and be sent a message with a link to manage their subscriptions. """ if request.method == 'POST': form = EmailForm(request.POST) if form.is_valid(): email = form.cleaned_data['email'] try: # Try it - basket will return an error if the email is unknown basket.send_recovery_message(email) except basket.BasketException as e: # Was it that their email was not known? if e.status_code == 404: # Tell them, give them a link to go subscribe if they want url = reverse('newsletter.mozilla-and-you') form.errors['email'] = \ form.error_class([unknown_address_text % url]) else: # Log the details log.exception("Error sending recovery message") # and tell the user that something went wrong form.errors['__all__'] = form.error_class([general_error]) else: messages.add_message(request, messages.INFO, recovery_text) # Redir as GET, signalling success return redirect(request.path + "?success") elif 'success' in request.GET: # We were redirected after a successful submission. # A message will be displayed; don't display the form again. form = None else: form = EmailForm() return l10n_utils.render( request, "newsletter/recovery.html", { 'form': form, })
def set_country(request, token): """Allow a user to set their country""" initial = {} countrycode = get_geo_from_request(request) if countrycode: initial['country'] = countrycode.lower() form = CountrySelectForm('en-US', data=request.POST or None, initial=initial) if form.is_valid(): try: basket.request('post', 'user-meta', data=form.cleaned_data, token=token) except basket.BasketException: log.exception("Error updating user's country in basket") messages.add_message( request, messages.ERROR, general_error ) else: return redirect(reverse('newsletter.country_success')) return l10n_utils.render(request, 'newsletter/country.html', {'form': form})
def json_file_validation(request, addon_id, addon, file_id): file = get_object_or_404(File, id=file_id) if not file.has_been_validated: try: v_result = tasks.file_validator(file.id) except Exception: log.exception('file_validator(%s)' % file.id) return { 'validation': '', 'error': "\n".join( traceback.format_exception(*sys.exc_info())), } else: v_result = file.validation validation = json.loads(v_result.validation) prepare_validation_results(validation) r = dict(validation=validation, error=None) return r
def wait_to_start(request): """ Wait until the transaction is in a ready state. Serve JS that polls for transaction state. When ready, redirect to the Bango payment URL using the generated billing configuration ID. """ try: trans = solitude.get_transaction(request.session['trans_id']) except ValueError: trans = {'status': None} if trans['status'] in constants.STATUS_ENDED: log.exception('Attempt to restart finished transaction.') return _error(request, msg=_('Transaction has already ended.')) if trans['status'] == constants.STATUS_PENDING: # The transaction is ready; no need to wait for it. return http.HttpResponseRedirect(_bango_start_url(trans['uid_pay'])) return render(request, 'pay/wait-to-start.html')
def get_newsletters(): """Return a dictionary with our information about newsletters. Keys are the internal keys we use to designate newsletters to basket. Values are dictionaries with the remaining newsletter information. If we cannot get through to basket, return a default set of newsletters from basket_data.json. """ # Get the newsletter data from basket - it's a dictionary of dictionaries # Cache it for a little while (300 secs = 5 minutes) data = cache.get(NEWSLETTERS_CACHE_KEY) if data is None: try: data = basket.get_newsletters() except basket.BasketException: log.exception("Error getting newsletters from basket") return get_local_basket_newsletters_data() # Cache for an hour - newsletters very rarely change cache.set(NEWSLETTERS_CACHE_KEY, data, NEWSLETTERS_CACHE_TIMEOUT) return data
def wrapper(request, *args, **kw): raw_sig_request = request.GET.get('r') or request.POST.get('r') if not raw_sig_request: return http.HttpResponseBadRequest('r was not in request') raw_sig_request = str(raw_sig_request) allowed = False try: sig_request = jwt.decode(raw_sig_request, verify=False) except jwt.DecodeError: log.exception('signed request was invalid') client_key = settings.API_CLIENTS.get(sig_request['iss']) if not client_key: return http.HttpResponseBadRequest() try: jwt.decode(raw_sig_request, client_key, verify=True) allowed = True except jwt.DecodeError: log.exception('signed request for %s was invalid') if not allowed: return http.HttpResponseForbidden() return view(request, raw_sig_request, sig_request, *args, **kw)
def upload(request, raw_sig_request, sig_request): if not os.path.exists(settings.UPLOAD_TEMP_DIR): log.info('creating upload temp dir') os.makedirs(settings.UPLOAD_TEMP_DIR) key, file = request.FILES.items()[0] _, ext = os.path.splitext(key) path = os.path.join(settings.UPLOAD_TEMP_DIR, '%s%s' % (uuid.uuid4(), ext)) hash = hashlib.sha1() with open(path, 'wb') as fp: for chunk in file.chunks(): hash.update(chunk) fp.write(chunk) sha1 = hash.hexdigest() user_email = sig_request['iss'] email, c = VerifiedEmail.objects.get_or_create(email=user_email) # Check the session. try: session = SyncSession.objects.get(email=email, is_active=True) except: log.exception('joining session for %s in upload' % email.email) return http.HttpResponseBadRequest('error joining session') # Check for existing files. if TrackFile.objects.filter(sha1=sha1, is_active=True).count(): log.info('client uploaded a file that already exists: %s' % sha1) os.unlink(path) return http.HttpResponseBadRequest('track already exists') log.info('uploaded %r for %s' % (fp.name, email.email)) sha1_from_client = str(sig_request['request']['sha1']) if sha1_from_client != sha1: log.info('client computed hash %s did not match server ' 'computed hash %s' % (sha1_from_client, sha1)) os.unlink(path) return http.HttpResponseBadRequest('sha1 hash did not match') tasks.process_file.delay(email.email, fp.name, session.session_key) return http.HttpResponse('cool')
def page(name, tmpl, decorators=None, **kwargs): # The URL pattern is the name with a forced trailing slash if not # empty pattern = r'^%s/$' % name if name else r'^$' # Set the name of the view to the template path replaced with dots (base, ext) = os.path.splitext(tmpl) name = base.replace('/', '.') # we don't have a caching backend yet, so no csrf (it's just a # newsletter form anyway) @csrf_exempt def _view(request): return l10n_utils.render(request, tmpl, kwargs) # This is for graphite so that we can differentiate pages _view.page_name = name if newrelic: # Name this in New Relic to differentiate pages newrelic.agent.set_transaction_name( 'mozorg.util.page:' + name.replace('.', '_')) # Apply decorators if decorators: if callable(decorators): _view = decorators(_view) else: try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=name)
def upload(request, raw_sig_request, sig_request): if not os.path.exists(settings.UPLOAD_TEMP_DIR): log.info("creating upload temp dir") os.makedirs(settings.UPLOAD_TEMP_DIR) key, file = request.FILES.items()[0] _, ext = os.path.splitext(key) path = os.path.join(settings.UPLOAD_TEMP_DIR, "%s%s" % (uuid.uuid4(), ext)) hash = hashlib.sha1() with open(path, "wb") as fp: for chunk in file.chunks(): hash.update(chunk) fp.write(chunk) sha1 = hash.hexdigest() user_email = sig_request["iss"] email, c = VerifiedEmail.objects.get_or_create(email=user_email) # Check the session. try: session = SyncSession.objects.get(email=email, is_active=True) except: log.exception("joining session for %s in upload" % email.email) return http.HttpResponseBadRequest("error joining session") # Check for existing files. if TrackFile.objects.filter(sha1=sha1, is_active=True).count(): log.info("client uploaded a file that already exists: %s" % sha1) os.unlink(path) return http.HttpResponseBadRequest("track already exists") log.info("uploaded %r for %s" % (fp.name, email.email)) sha1_from_client = str(sig_request["request"]["sha1"]) if sha1_from_client != sha1: log.info("client computed hash %s did not match server " "computed hash %s" % (sha1_from_client, sha1)) os.unlink(path) return http.HttpResponseBadRequest("sha1 hash did not match") tasks.process_file.delay(email.email, fp.name, session.session_key) return http.HttpResponse("cool")
def page(name, tmpl, decorators=None, **kwargs): # The URL pattern is the name with a forced trailing slash if not # empty pattern = r'^%s/$' % name if name else r'^$' # Set the name of the view to the template path replaced with dots (base, ext) = os.path.splitext(tmpl) name = base.replace('/', '.') # we don't have a caching backend yet, so no csrf (it's just a # newsletter form anyway) @csrf_exempt def _view(request): if newrelic: # Name this in New Relic to differentiate pages newrelic.agent.set_transaction_name( 'mozorg.util.page:' + name.replace('.', '_')) return l10n_utils.render(request, tmpl, kwargs) # This is for graphite so that we can differentiate pages _view.page_name = name # Apply decorators if decorators: if callable(decorators): _view = decorators(_view) else: try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=name)
def checkfiles(request, raw_sig_request, sig_request): try: session_key = sig_request["request"]["session_key"] sha1s = sig_request["request"]["sha1s"] except KeyError: log.exception("in checkfiles") return http.HttpResponseBadRequest("malformed request") session = SyncSession.objects.get(pk=session_key) all_files = TrackFile.objects.filter(sha1__in=sha1s, is_active=True) existing = set() log.info("checking files for upload session %s" % session_key) print("checking files for upload session %s" % session_key) for sh in all_files: existing.add(sh.sha1) # touch the files and track to prevent deletion on sync. all_files.update(session=session) (Track.objects.filter(files__sha1__in=sha1s, is_active=True).update(session=session)) check = {} for sh in sha1s: check[sh] = bool(sh in existing) return {"sha1s": check}
def one_newsletter_signup(request, template_name): success = False # not in a footer, but we use the same form form = NewsletterFooterForm(request.locale, request.POST or None) if form.is_valid(): data = form.cleaned_data request.newsletter_lang = data.get("lang", "en") or "en" kwargs = {"format": data["fmt"]} # add optional data kwargs.update(dict((k, data[k]) for k in ["country", "lang", "source_url"] if data[k])) try: basket.subscribe(data["email"], data["newsletter"], **kwargs) except basket.BasketException: log.exception("Error subscribing %s to newsletter %s" % (data["email"], data["newsletter"])) form.errors["__all__"] = form.error_class([general_error]) else: success = True request.newsletter_form = form request.newsletter_success = success return l10n_utils.render(request, template_name, {})
def checkfiles(request, raw_sig_request, sig_request): try: session_key = sig_request['request']['session_key'] sha1s = sig_request['request']['sha1s'] except KeyError: log.exception('in checkfiles') return http.HttpResponseBadRequest('malformed request') session = SyncSession.objects.get(pk=session_key) all_files = TrackFile.objects.filter(sha1__in=sha1s, is_active=True) existing = set() log.info('checking files for upload session %s' % session_key) print('checking files for upload session %s' % session_key) for sh in all_files: existing.add(sh.sha1) # touch the files and track to prevent deletion on sync. all_files.update(session=session) (Track.objects.filter(files__sha1__in=sha1s, is_active=True).update(session=session)) check = {} for sh in sha1s: check[sh] = bool(sh in existing) return {'sha1s': check}
def redirect(pattern, to, permanent=True, locale_prefix=True, anchor=None, name=None, query=None, vary=None, cache_timeout=12, decorators=None, re_flags=None, to_args=None, to_kwargs=None, prepend_locale=True, merge_query=False): """ Return a url matcher suited for urlpatterns. pattern: the regex against which to match the requested URL. to: either a url name that `reverse` will find, a url that will simply be returned, or a function that will be given the request and url captures, and return the destination. permanent: boolean whether to send a 301 or 302 response. locale_prefix: automatically prepend `pattern` with a regex for an optional locale in the url. This locale (or None) will show up in captured kwargs as 'locale'. anchor: if set it will be appended to the destination url after a '#'. name: if used in a `urls.py` the redirect URL will be available as the name for use in calls to `reverse()`. Does _NOT_ work if used in a `redirects.py` file. query: a dict of query params to add to the destination url. vary: if you used an HTTP header to decide where to send users you should include that header's name in the `vary` arg. cache_timeout: number of hours to cache this redirect. just sets the proper `cache-control` and `expires` headers. decorators: a callable (or list of callables) that will wrap the view used to redirect the user. equivalent to adding a decorator to any other view. re_flags: a string of any of the characters: "iLmsux". Will modify the `pattern` regex based on the documented meaning of the flags (see python re module docs). to_args: a tuple or list of args to pass to reverse if `to` is a url name. to_kwargs: a dict of keyword args to pass to reverse if `to` is a url name. prepend_locale: if true the redirect URL will be prepended with the locale from the requested URL. merge_query: merge the requested query params from the `query` arg with any query params from the request. Usage: urlpatterns = [ redirect(r'projects/$', 'mozorg.product'), redirect(r'^projects/seamonkey$', 'mozorg.product', locale_prefix=False), redirect(r'apps/$', 'https://marketplace.firefox.com'), redirect(r'firefox/$', 'firefox.new', name='firefox'), redirect(r'the/dude$', 'abides', query={'aggression': 'not_stand'}), ] """ if permanent: redirect_class = HttpResponsePermanentRedirect else: redirect_class = HttpResponseRedirect if locale_prefix: pattern = pattern.lstrip('^/') pattern = LOCALE_RE + pattern if re_flags: pattern = '(?{})'.format(re_flags) + pattern view_decorators = [] if cache_timeout is not None: view_decorators.append(cache_control_expires(cache_timeout)) if vary: if isinstance(vary, basestring): vary = [vary] view_decorators.append(vary_on_headers(*vary)) if decorators: if callable(decorators): view_decorators.append(decorators) else: view_decorators.extend(decorators) def _view(request, *args, **kwargs): # don't want to have 'None' in substitutions kwargs = {k: v or '' for k, v in kwargs.items()} args = [x or '' for x in args] # If it's a callable, call it and get the url out. if callable(to): to_value = to(request, *args, **kwargs) else: to_value = to if to_value.startswith('/') or HTTP_RE.match(to_value): redirect_url = to_value else: try: redirect_url = reverse(to_value, args=to_args, kwargs=to_kwargs) except NoReverseMatch: # Assume it's a URL redirect_url = to_value if prepend_locale and redirect_url.startswith('/') and kwargs.get('locale'): redirect_url = '/{locale}' + redirect_url.lstrip('/') # use info from url captures. if args or kwargs: redirect_url = strip_tags(force_text(redirect_url).format(*args, **kwargs)) if query: if merge_query: req_query = parse_qs(request.META.get('QUERY_STRING', '')) req_query.update(query) querystring = urlencode(req_query, doseq=True) else: querystring = urlencode(query, doseq=True) elif query is None: querystring = request.META.get('QUERY_STRING', '') else: querystring = '' if querystring: redirect_url = '?'.join([redirect_url, querystring]) if anchor: redirect_url = '#'.join([redirect_url, anchor]) if PROTOCOL_RELATIVE_RE.match(redirect_url): redirect_url = '/' + redirect_url.lstrip('/') return redirect_class(redirect_url) # Apply decorators try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(view_decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=name)
def newsletter_subscribe(request): if request.method == 'POST': newsletters = request.POST.get('newsletters', None) form = NewsletterFooterForm(newsletters, l10n_utils.get_locale(request), request.POST) errors = [] if form.is_valid(): data = form.cleaned_data kwargs = {'format': data['fmt']} # add optional data kwargs.update( dict((k, data[k]) for k in [ 'country', 'lang', 'source_url', 'first_name', 'last_name', ] if data[k])) # NOTE this is not a typo; Referrer is misspelled in the HTTP spec # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36 if not kwargs.get('source_url') and request.META.get( 'HTTP_REFERER'): kwargs['source_url'] = request.META['HTTP_REFERER'] try: basket.subscribe(data['email'], data['newsletters'], **kwargs) except basket.BasketException as e: if e.code == basket.errors.BASKET_INVALID_EMAIL: errors.append(str(invalid_email_address)) else: log.exception("Error subscribing %s to newsletter %s" % (data['email'], data['newsletters'])) errors.append(str(general_error)) else: if 'email' in form.errors: errors.append(ftl('newsletter-form-please-enter-a-valid')) if 'privacy' in form.errors: errors.append(ftl('newsletter-form-you-must-agree-to')) for fieldname in ('fmt', 'lang', 'country'): if fieldname in form.errors: errors.extend(form.errors[fieldname]) # form error messages may contain unsanitized user input errors = list(map(escape, errors)) if request.is_ajax(): # return JSON if errors: resp = { 'success': False, 'errors': errors, } else: resp = {'success': True} return JsonResponse(resp) else: ctx = {'newsletter_form': form} if not errors: ctx['success'] = True return l10n_utils.render(request, 'newsletter/index.html', ctx) return l10n_utils.render(request, 'newsletter/index.html')
def existing(request, token=None): """Manage subscriptions. If token is provided, user can manage their existing subscriptions, to subscribe, unsubscribe, change email or language preferences, etc. If no token is provided, user can fill in their email and language preferences and sign up for newsletters. @param HTTPRequest request: Django request object @param string token: A UUID that identifies this user to the backend. It's sent to users in each newsletter as part of a link to this page, so they can manage their subscriptions without needing an account somewhere with userid & password. """ locale = l10n_utils.get_locale(request) if not token: return redirect(reverse('newsletter.recovery')) if not UUID_REGEX.match(token): # Bad token messages.add_message(request, messages.ERROR, bad_token) # Redirect to the recovery page return redirect(reverse('newsletter.recovery')) if waffle.switch('newsletter-maintenance-mode'): return l10n_utils.render(request, 'newsletter/existing.html') unsub_parm = None # Example user: # # {u'lang': u'en', # u'format': u'H', # u'country': u'us', # u'newsletters': [u'firefox-tips', u'mobile'], # u'created-date': u'1/30/2013 12:46:05 PM', # u'token': u'some-uuid', # u'email': u'*****@*****.**' # } has_fxa = 'fxa' in request.GET user = None if token: try: # ask for fxa status if not passed in the URL params = None if has_fxa else {'fxa': 1} user = basket.request('get', 'user', token=token, params=params) except basket.BasketNetworkException: # Something wrong with basket backend, no point in continuing, # we'd probably fail to subscribe them anyway. log.exception("Basket timeout") messages.add_message(request, messages.ERROR, general_error) return l10n_utils.render(request, 'newsletter/existing.html') except basket.BasketException as e: log.exception("FAILED to get user from token (%s)", e.desc) if not user: # Bad or no token messages.add_message(request, messages.ERROR, bad_token) # Redirect to the recovery page return redirect(reverse('newsletter.recovery')) # if `has_fxa` not returned from basket, set it from the URL user.setdefault('has_fxa', has_fxa) # Get the newsletter data - it's a dictionary of dictionaries newsletter_data = utils.get_newsletters() # Figure out which newsletters to display, and whether to show them # as already subscribed. initial = [] for newsletter, data in newsletter_data.items(): # Only show a newsletter if it has ['active'] == True and # ['show'] == True or the user is already subscribed if not data.get('active', False): continue if (data.get('show', False) or newsletter in user['newsletters'] or (user['has_fxa'] and newsletter in settings.FXA_NEWSLETTERS and any( locale.startswith(l) for l in settings.FXA_NEWSLETTERS_LOCALES))): langs = data['languages'] nstrings = NEWSLETTER_STRINGS.get(newsletter) if nstrings: if newsletter == 'firefox-accounts-journey' and locale.startswith( 'en'): # alternate english title title = u'Firefox Account Tips' else: title = nstrings['title'] description = nstrings.get('description', u'') else: # Firefox Marketplace for Desktop/Android/Firefox OS should be # shorten in the titles title = _(data['title'].replace('Firefox Marketplace for ', '')) description = _(data['description']) form_data = { 'title': Markup(title), 'subscribed_radio': newsletter in user['newsletters'], 'subscribed_check': newsletter in user['newsletters'], 'newsletter': newsletter, 'description': Markup(description), 'english_only': len(langs) == 1 and langs[0].startswith('en'), 'indented': data.get('indent', False), } if 'order' in data: form_data['order'] = data['order'] initial.append(form_data) # Sort by 'order' field if we were given it; otherwise, by title if initial: keyfield = 'order' if 'order' in initial[0] else 'title' initial.sort(key=itemgetter(keyfield)) NewsletterFormSet = formset_factory(NewsletterForm, extra=0, max_num=len(initial)) if request.method == 'POST': form_kwargs = {} # Temporary form so we can see if they checked 'remove_all'. If # they did, no point in validating the newsletters formset and it would # look dumb to complain about it. form = ManageSubscriptionsForm(locale, data=request.POST, initial=user) remove_all = form.is_valid() and form.cleaned_data['remove_all'] formset_is_valid = False if remove_all: # We don't care about the newsletter formset formset_is_valid = True # Make an initialized one in case we fall through to the bottom formset = NewsletterFormSet(initial=initial) else: # We do need to validate the newsletter formset formset = NewsletterFormSet(request.POST, initial=initial) # Set `newsletters` to the list of newsletters they want. # After this, we don't need the formset anymore. newsletters = None if formset.is_valid(): formset_is_valid = True # What newsletters do they say they want to be subscribed to? newsletters = set([ subform.cleaned_data['newsletter'] for subform in formset if (subform.cleaned_data['subscribed_radio'] or subform.cleaned_data['subscribed_check']) ]) form_kwargs['newsletters'] = newsletters form = ManageSubscriptionsForm(locale, data=request.POST, initial=user, **form_kwargs) if formset_is_valid and form.is_valid(): data = form.cleaned_data # Update their format and locale information, if it has changed. # Also pass their updated list of newsletters they want to be # subscribed to, for basket to implement. kwargs = {} if settings.BASKET_API_KEY: kwargs['api_key'] = settings.BASKET_API_KEY for k in ['lang', 'format', 'country']: if user[k] != data[k]: kwargs[k] = data[k] if not remove_all: kwargs['newsletters'] = ",".join(newsletters) if kwargs: # always send lang so basket doesn't try to guess kwargs['lang'] = data['lang'] try: basket.update_user(token, **kwargs) except basket.BasketException: log.exception("Error updating user in basket") messages.add_message(request, messages.ERROR, general_error) return l10n_utils.render(request, 'newsletter/existing.html') # If they chose to remove all, tell basket that they've opted out if remove_all: try: basket.unsubscribe(token, user['email'], optout=True) except (basket.BasketException, requests.Timeout): log.exception("Error updating subscriptions in basket") messages.add_message(request, messages.ERROR, general_error) return l10n_utils.render(request, 'newsletter/existing.html') # We need to pass their token to the next view url = reverse('newsletter.updated') \ + "?unsub=%s&token=%s" % (UNSUB_UNSUBSCRIBED_ALL, token) return redirect(url) # We're going to redirect, so the only way to tell the next # view that we should display the welcome message in the # template is to modify the URL url = reverse('newsletter.updated') if unsub_parm: url += "?unsub=%s" % unsub_parm return redirect(url) # FALL THROUGH so page displays errors else: form = ManageSubscriptionsForm(locale, initial=user) formset = NewsletterFormSet(initial=initial) # For the template, we want a dictionary whose keys are language codes # and each value is the list of newsletter keys that are available in # that language code. newsletter_languages = defaultdict(list) for newsletter, data in newsletter_data.items(): for lang in data['languages']: newsletter_languages[lang].append(newsletter) newsletter_languages = mark_safe(json.dumps(newsletter_languages)) # We also want a list of the newsletters the user is already subscribed to already_subscribed = mark_safe(json.dumps(user['newsletters'])) context = { 'did_confirm': request.GET.get('confirm', None) == '1', 'form': form, 'formset': formset, 'newsletter_languages': newsletter_languages, 'newsletters_subscribed': already_subscribed, 'email': user['email'], } return l10n_utils.render(request, 'newsletter/existing.html', context)
def redirect(pattern, to, permanent=True, locale_prefix=True, anchor=None, name=None, query=None, vary=None, cache_timeout=12, decorators=None, re_flags=None, to_args=None, to_kwargs=None, prepend_locale=True, merge_query=False): """ Return a url matcher suited for urlpatterns. pattern: the regex against which to match the requested URL. to: either a url name that `reverse` will find, a url that will simply be returned, or a function that will be given the request and url captures, and return the destination. permanent: boolean whether to send a 301 or 302 response. locale_prefix: automatically prepend `pattern` with a regex for an optional locale in the url. This locale (or None) will show up in captured kwargs as 'locale'. anchor: if set it will be appended to the destination url after a '#'. name: if used in a `urls.py` the redirect URL will be available as the name for use in calls to `reverse()`. Does _NOT_ work if used in a `redirects.py` file. query: a dict of query params to add to the destination url. vary: if you used an HTTP header to decide where to send users you should include that header's name in the `vary` arg. cache_timeout: number of hours to cache this redirect. just sets the proper `cache-control` and `expires` headers. decorators: a callable (or list of callables) that will wrap the view used to redirect the user. equivalent to adding a decorator to any other view. re_flags: a string of any of the characters: "iLmsux". Will modify the `pattern` regex based on the documented meaning of the flags (see python re module docs). to_args: a tuple or list of args to pass to reverse if `to` is a url name. to_kwargs: a dict of keyword args to pass to reverse if `to` is a url name. prepend_locale: if true the redirect URL will be prepended with the locale from the requested URL. merge_query: merge the requested query params from the `query` arg with any query params from the request. Usage: urlpatterns = [ redirect(r'projects/$', 'mozorg.product'), redirect(r'^projects/seamonkey$', 'mozorg.product', locale_prefix=False), redirect(r'apps/$', 'https://marketplace.firefox.com'), redirect(r'firefox/$', 'firefox.new', name='firefox'), redirect(r'the/dude$', 'abides', query={'aggression': 'not_stand'}), ] """ if permanent: redirect_class = HttpResponsePermanentRedirect else: redirect_class = HttpResponseRedirect if locale_prefix: pattern = pattern.lstrip('^/') pattern = LOCALE_RE + pattern if re_flags: pattern = '(?{})'.format(re_flags) + pattern view_decorators = [] if cache_timeout is not None: view_decorators.append(cache_control_expires(cache_timeout)) if vary: if isinstance(vary, basestring): vary = [vary] view_decorators.append(vary_on_headers(*vary)) if decorators: if callable(decorators): view_decorators.append(decorators) else: view_decorators.extend(decorators) def _view(request, *args, **kwargs): # don't want to have 'None' in substitutions kwargs = {k: v or '' for k, v in kwargs.items()} args = [x or '' for x in args] # If it's a callable, call it and get the url out. if callable(to): to_value = to(request, *args, **kwargs) else: to_value = to if to_value.startswith('/') or HTTP_RE.match(to_value): redirect_url = to_value else: try: redirect_url = reverse(to_value, args=to_args, kwargs=to_kwargs) except NoReverseMatch: # Assume it's a URL redirect_url = to_value if prepend_locale and redirect_url.startswith('/') and kwargs.get('locale'): redirect_url = '/{locale}' + redirect_url.lstrip('/') # use info from url captures. if args or kwargs: redirect_url = strip_tags(force_text(redirect_url).format(*args, **kwargs)) if query: if merge_query: req_query = parse_qs(request.META.get('QUERY_STRING')) req_query.update(query) querystring = urlencode(req_query, doseq=True) else: querystring = urlencode(query, doseq=True) elif query is None: querystring = request.META.get('QUERY_STRING') else: querystring = '' if querystring: redirect_url = '?'.join([redirect_url, querystring]) if anchor: redirect_url = '#'.join([redirect_url, anchor]) if PROTOCOL_RELATIVE_RE.match(redirect_url): redirect_url = '/' + redirect_url.lstrip('/') return redirect_class(redirect_url) # Apply decorators try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(view_decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=name)
def newsletter_subscribe(request): if request.method == "POST": newsletters = request.POST.getlist("newsletters") form = NewsletterFooterForm(newsletters, l10n_utils.get_locale(request), request.POST) errors = [] if form.is_valid(): data = form.cleaned_data kwargs = {"format": data["fmt"]} # add optional data kwargs.update({ k: data[k] for k in [ "country", "lang", "source_url", "first_name", "last_name", ] if data[k] }) # NOTE this is not a typo; Referrer is misspelled in the HTTP spec # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36 if not kwargs.get("source_url") and request.headers.get("Referer"): kwargs["source_url"] = request.headers["Referer"] # Convert data["newsletters"] to a comma separated string. newsletters = data["newsletters"] if isinstance(newsletters, list): newsletters = ",".join(newsletters) try: basket.subscribe(data["email"], newsletters, **kwargs) except basket.BasketException as e: if e.code == basket.errors.BASKET_INVALID_EMAIL: errors.append(str(invalid_email_address)) else: log.exception( f"Error subscribing {data['email']} to newsletter(s) {newsletters}" ) errors.append(str(general_error)) else: if "email" in form.errors: errors.append(ftl("newsletter-form-please-enter-a-valid")) if "privacy" in form.errors: errors.append(ftl("newsletter-form-you-must-agree-to")) for fieldname in ("newsletters", "fmt", "lang", "country"): if fieldname in form.errors: errors.extend(form.errors[fieldname]) # form error messages may contain unsanitized user input errors = [escape(e) for e in errors] if request.headers.get("x-requested-with") == "XMLHttpRequest": # return JSON if errors: resp = { "success": False, "errors": errors, } else: resp = {"success": True} return JsonResponse(resp) else: ctx = {"newsletter_form": form} if not errors: ctx["success"] = True return l10n_utils.render(request, "newsletter/index.html", ctx, ftl_files=FTL_FILES) return l10n_utils.render(request, "newsletter/index.html", ftl_files=FTL_FILES)
def transaction_refund(request, tx_uuid): contrib = get_object_or_404(Contribution, uuid=tx_uuid, type=amo.CONTRIB_PURCHASE) refund_contribs = contrib.get_refund_contribs() refund_contrib = refund_contribs[0] if refund_contribs.exists() else None if refund_contrib: messages.error(request, _("A refund has already been processed.")) return redirect(reverse("lookup.transaction_summary", args=[tx_uuid])) form = TransactionRefundForm(request.POST) if not form.is_valid(): return jingo.render( request, "lookup/transaction_summary.html", dict( {"uuid": tx_uuid, "tx_refund_form": form, "tx_form": TransactionSearchForm()}.items() + _transaction_summary(tx_uuid).items() ), ) data = {"uuid": contrib.transaction_id, "manual": form.cleaned_data["manual"]} if settings.BANGO_FAKE_REFUNDS: data["fake_response_status"] = {"responseCode": form.cleaned_data["fake"]} try: res = client.api.bango.refund.post(data) except (HttpClientError, HttpServerError): # Either doing something not supposed to or Solitude had an issue. log.exception("Refund error: %s" % tx_uuid) messages.error(request, _("You cannot make a refund request for this transaction.")) return redirect(reverse("lookup.transaction_summary", args=[tx_uuid])) if res["status"] in [PENDING, COMPLETED]: # Create refund Contribution by cloning the payment Contribution. refund_contrib = Contribution.objects.get(id=contrib.id) refund_contrib.id = None refund_contrib.save() refund_contrib.update( type=amo.CONTRIB_REFUND, related=contrib, uuid=hashlib.md5(str(uuid.uuid4())).hexdigest(), amount=-refund_contrib.amount if refund_contrib.amount else None, transaction_id=res["uuid"], ) if res["status"] == PENDING: # Create pending Refund. refund_contrib.enqueue_refund( amo.REFUND_PENDING, request.amo_user, refund_reason=form.cleaned_data["refund_reason"] ) log.info("Refund pending: %s" % tx_uuid) email_buyer_refund_pending(contrib) messages.success(request, _("Refund for this transaction now pending.")) elif res["status"] == COMPLETED: # Create approved Refund. refund_contrib.enqueue_refund( amo.REFUND_APPROVED, request.amo_user, refund_reason=form.cleaned_data["refund_reason"] ) log.info("Refund approved: %s" % tx_uuid) email_buyer_refund_approved(contrib) messages.success(request, _("Refund for this transaction successfully approved.")) elif res["status"] == FAILED: # Bango no like. log.error("Refund failed: %s" % tx_uuid) messages.error(request, _("Refund request for this transaction failed.")) return redirect(reverse("lookup.transaction_summary", args=[tx_uuid]))
def wrapper(request, *args, **kw): try: return f(request, *args, **kw) except: log.exception('in request') raise
def existing(request, token=None): """Manage subscriptions. If token is provided, user can manage their existing subscriptions, to subscribe, unsubscribe, change email or language preferences, etc. If no token is provided, user can fill in their email and language preferences and sign up for newsletters. @param HTTPRequest request: Django request object @param string token: A UUID that identifies this user to the backend. It's sent to users in each newsletter as part of a link to this page, so they can manage their subscriptions without needing an account somewhere with userid & password. """ locale = getattr(request, 'locale', 'en-US') if not token: return redirect(reverse('newsletter.recovery')) if not UUID_REGEX.match(token): # Bad token messages.add_message(request, messages.ERROR, bad_token) # Redirect to the recovery page return redirect(reverse('newsletter.recovery')) unsub_parm = None # Example user: # # {u'lang': u'en', # u'format': u'H', # u'country': u'us', # u'newsletters': [u'firefox-tips', u'mobile'], # u'created-date': u'1/30/2013 12:46:05 PM', # u'token': u'some-uuid', # u'email': u'*****@*****.**' # } user_exists = False if token: try: user = basket.user(token) except basket.BasketNetworkException: # Something wrong with basket backend, no point in continuing, # we'd probably fail to subscribe them anyway. log.exception("Basket timeout") messages.add_message(request, messages.ERROR, general_error) return l10n_utils.render(request, 'newsletter/existing.html') except basket.BasketException as e: log.exception("FAILED to get user from token (%s)", e.desc) else: user_exists = True if not user_exists: # Bad or no token messages.add_message(request, messages.ERROR, bad_token) # Redirect to the recovery page return redirect(reverse('newsletter.recovery')) # Get the newsletter data - it's a dictionary of dictionaries newsletter_data = utils.get_newsletters() # Figure out which newsletters to display, and whether to show them # as already subscribed. initial = [] for newsletter, data in newsletter_data.iteritems(): # Only show a newsletter if it has ['active'] == True and # ['show'] == True or the user is already subscribed if not data.get('active', False): continue if data.get('show', False) or newsletter in user['newsletters']: langs = data['languages'] nstrings = NEWSLETTER_STRINGS.get(newsletter) if nstrings: title = nstrings['title'] description = nstrings.get('description', u'') else: # Firefox Marketplace for Desktop/Android/Firefox OS should be # shorten in the titles title = _(data['title'].replace('Firefox Marketplace for ', '')) description = _(data['description']) form_data = { 'title': Markup(title), 'subscribed_radio': newsletter in user['newsletters'], 'subscribed_check': newsletter in user['newsletters'], 'newsletter': newsletter, 'description': Markup(description), 'english_only': len(langs) == 1 and langs[0].startswith('en'), } if 'order' in data: form_data['order'] = data['order'] initial.append(form_data) # Sort by 'order' field if we were given it; otherwise, by title if initial: keyfield = 'order' if 'order' in initial[0] else 'title' initial.sort(key=itemgetter(keyfield)) NewsletterFormSet = formset_factory(NewsletterForm, extra=0, max_num=len(initial)) if request.method == 'POST': form_kwargs = {} # Temporary form so we can see if they checked 'remove_all'. If # they did, no point in validating the newsletters formset and it would # look dumb to complain about it. form = ManageSubscriptionsForm(locale, data=request.POST, initial=user) remove_all = form.is_valid() and form.cleaned_data['remove_all'] formset_is_valid = False if remove_all: # We don't care about the newsletter formset formset_is_valid = True # Make an initialized one in case we fall through to the bottom formset = NewsletterFormSet(initial=initial) else: # We do need to validate the newsletter formset formset = NewsletterFormSet(request.POST, initial=initial) # Set `newsletters` to the list of newsletters they want. # After this, we don't need the formset anymore. newsletters = None if formset.is_valid(): formset_is_valid = True # What newsletters do they say they want to be subscribed to? newsletters = set([subform.cleaned_data['newsletter'] for subform in formset if (subform.cleaned_data['subscribed_radio'] or subform.cleaned_data['subscribed_check'])]) form_kwargs['newsletters'] = newsletters form = ManageSubscriptionsForm(locale, data=request.POST, initial=user, **form_kwargs) if formset_is_valid and form.is_valid(): data = form.cleaned_data # Update their format and locale information, if it has changed. # Also pass their updated list of newsletters they want to be # subscribed to, for basket to implement. kwargs = {} for k in ['lang', 'format', 'country']: if user[k] != data[k]: kwargs[k] = data[k] if not remove_all: kwargs['newsletters'] = ",".join(newsletters) if kwargs: try: basket.update_user(token, **kwargs) except basket.BasketException: log.exception("Error updating user in basket") messages.add_message( request, messages.ERROR, general_error ) return l10n_utils.render(request, 'newsletter/existing.html') # If they chose to remove all, tell basket that they've opted out if remove_all: try: basket.unsubscribe(token, user['email'], optout=True) except (basket.BasketException, requests.Timeout): log.exception("Error updating subscriptions in basket") messages.add_message( request, messages.ERROR, general_error ) return l10n_utils.render(request, 'newsletter/existing.html') # We need to pass their token to the next view url = reverse('newsletter.updated') \ + "?unsub=%s&token=%s" % (UNSUB_UNSUBSCRIBED_ALL, token) return redirect(url) # We're going to redirect, so the only way to tell the next # view that we should display the welcome message in the # template is to modify the URL url = reverse('newsletter.updated') if unsub_parm: url += "?unsub=%s" % unsub_parm return redirect(url) # FALL THROUGH so page displays errors else: form = ManageSubscriptionsForm( locale, initial=user ) formset = NewsletterFormSet(initial=initial) # For the template, we want a dictionary whose keys are language codes # and each value is the list of newsletter keys that are available in # that language code. newsletter_languages = defaultdict(list) for newsletter, data in newsletter_data.iteritems(): for lang in data['languages']: newsletter_languages[lang].append(newsletter) newsletter_languages = mark_safe(json.dumps(newsletter_languages)) # We also want a list of the newsletters the user is already subscribed # to already_subscribed = mark_safe(json.dumps(user['newsletters'])) context = { 'form': form, 'formset': formset, 'newsletter_languages': newsletter_languages, 'newsletters_subscribed': already_subscribed, 'email': user['email'], } return l10n_utils.render(request, 'newsletter/existing.html', context)
form.cleaned_data['req'], settings.DOMAIN, # JWT audience. form.secret, required_keys=('request.id', 'request.pricePoint', # A price tier we'll lookup. 'request.name', 'request.description')) except (TypeError, InvalidJWT, RequestExpired), exc: log.exception('calling verify_jwt') return _error(request, exception=exc) # Assert pricePoint is valid. try: marketplace.get_price(pay_req['request']['pricePoint']) except (TierNotFound, HttpClientError), exc: log.exception('calling verifying tier') return _error(request, exception=exc) try: iss = Issuer.objects.get(issuer_key=form.key) except Issuer.DoesNotExist: iss = None # marketplace # TODO(Kumar) fix this for reals. See bug 820198. desc = pay_req['request']['description'] if len(desc) > 255: desc = desc[0:255] # Before we verify the user's PIN let's save some # time and get the transaction configured via Bango in the # background.
def transaction_refund(request, tx_uuid): contrib = get_object_or_404(Contribution, uuid=tx_uuid, type=amo.CONTRIB_PURCHASE) refund_contribs = contrib.get_refund_contribs() refund_contrib = refund_contribs[0] if refund_contribs.exists() else None if refund_contrib: messages.error(request, _('A refund has already been processed.')) return redirect(reverse('lookup.transaction_summary', args=[tx_uuid])) form = TransactionRefundForm(request.POST) if not form.is_valid(): return jingo.render( request, 'lookup/transaction_summary.html', dict({ 'uuid': tx_uuid, 'tx_refund_form': form, 'tx_form': TransactionSearchForm() }.items() + _transaction_summary(tx_uuid).items())) try: res = client.api.bango.refund.post({'uuid': contrib.transaction_id}) except (HttpClientError, HttpServerError): # Either doing something not supposed to or Solitude had an issue. log.exception('Refund error: %s' % tx_uuid) messages.error( request, _('You cannot make a refund request for this transaction.')) return redirect(reverse('lookup.transaction_summary', args=[tx_uuid])) if res['status'] in [PENDING, COMPLETED]: # Create refund Contribution by cloning the payment Contribution. refund_contrib = Contribution.objects.get(id=contrib.id) refund_contrib.id = None refund_contrib.save() refund_contrib.update( type=amo.CONTRIB_REFUND, related=contrib, uuid=hashlib.md5(str(uuid.uuid4())).hexdigest(), amount=-refund_contrib.amount if refund_contrib.amount else None, transaction_id=client.get(res['transaction'])['uuid']) if res['status'] == PENDING: # Create pending Refund. refund_contrib.enqueue_refund( amo.REFUND_PENDING, request.amo_user, refund_reason=form.cleaned_data['refund_reason']) log.info('Refund pending: %s' % tx_uuid) email_buyer_refund_pending(contrib) messages.success(request, _('Refund for this transaction now pending.')) elif res['status'] == COMPLETED: # Create approved Refund. refund_contrib.enqueue_refund( amo.REFUND_APPROVED, request.amo_user, refund_reason=form.cleaned_data['refund_reason']) log.info('Refund approved: %s' % tx_uuid) email_buyer_refund_approved(contrib) messages.success( request, _('Refund for this transaction successfully approved.')) elif res['status'] == FAILED: # Bango no like. log.error('Refund failed: %s' % tx_uuid) messages.error(request, _('Refund request for this transaction failed.')) return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))
def page(name, tmpl, decorators=None, url_name=None, **kwargs): """ Define a bedrock page. The URL name is the template name, with the extension stripped and the slashes changed to dots. So if tmpl="path/to/template.html", then the page's URL name will be "path.to.template". Set the `url_name` parameter to override this name. @param name: The URL regex pattern. If not empty, a trailing slash is added automatically, so it shouldn't be included in the parameter value. @param tmpl: The template name. Also used to come up with the URL name. @param decorators: A decorator or an iterable of decorators that should be applied to the view. @param url_name: The value to use as the URL name, default is to coerce the template path into a name as described above. @param active_locales: A list of locale codes that should be active for this page regardless of the state of the lang files. Useful for pages with locale- specific templates or non-English text in the template. Ignores the lang file activation tags. @param add_active_locales: A list of locale codes that should be active for this page in addition to those from the lang files. @param kwargs: Any additional arguments are passed to l10n_utils.render as the context. """ pattern = r'^%s/$' % name if name else r'^$' if url_name is None: # Set the name of the view to the template path replaced with dots (base, ext) = os.path.splitext(tmpl) url_name = base.replace('/', '.') # we don't have a caching backend yet, so no csrf (it's just a # newsletter form anyway) @csrf_exempt def _view(request): if newrelic: # Name this in New Relic to differentiate pages newrelic.agent.set_transaction_name('mozorg.util.page:' + url_name.replace('.', '_')) kwargs.setdefault('urlname', url_name) # skip l10n if path exempt name_prefix = request.path_info.split('/', 2)[1] if name_prefix in settings.SUPPORTED_NONLOCALES: return django_render(request, tmpl, kwargs) return l10n_utils.render(request, tmpl, kwargs) # This is for graphite so that we can differentiate pages _view.page_name = url_name # Apply decorators if decorators: if callable(decorators): _view = decorators(_view) else: try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=url_name)
def newsletter_subscribe(request): if request.method == 'POST': newsletters = request.POST.get('newsletters', None) form = NewsletterFooterForm(newsletters, l10n_utils.get_locale(request), request.POST) errors = [] if form.is_valid(): data = form.cleaned_data kwargs = {'format': data['fmt']} # add optional data kwargs.update( dict((k, data[k]) for k in [ 'country', 'lang', 'source_url', 'first_name', 'last_name', ] if data[k])) try: basket.subscribe(data['email'], data['newsletters'], **kwargs) except basket.BasketException as e: if e.code == basket.errors.BASKET_INVALID_EMAIL: errors.append(unicode(invalid_email_address)) else: log.exception("Error subscribing %s to newsletter %s" % (data['email'], data['newsletters'])) errors.append(unicode(general_error)) else: if 'email' in form.errors: errors.append(_('Please enter a valid email address')) if 'privacy' in form.errors: errors.append(_('You must agree to the privacy notice')) for fieldname in ('fmt', 'lang', 'country'): if fieldname in form.errors: errors.extend(form.errors[fieldname]) # form error messages may contain unsanitized user input errors = map(escape, errors) if request.is_ajax(): # return JSON if errors: resp = { 'success': False, 'errors': errors, } else: resp = {'success': True} return HttpResponseJSON(resp) else: ctx = {'newsletter_form': form} if not errors: ctx['success'] = True return l10n_utils.render(request, 'newsletter/mozilla-and-you.html', ctx) return l10n_utils.render(request, 'newsletter/mozilla-and-you.html')
'request.chargebackURL')) except (TypeError, InvalidJWT, RequestExpired), exc: log.exception('calling verify_jwt') return _error(request, exception=exc, is_simulation=form.is_simulation) icon_urls = [] if pay_req['request'].get('icons'): icon_urls = pay_req['request']['icons'].values() # Verify that all URLs are valid. try: verify_urls(pay_req['request']['postbackURL'], pay_req['request']['chargebackURL'], *icon_urls, is_simulation=form.is_simulation) except ValueError, exc: log.exception('invalid URLs') return _error(request, exception=exc, is_simulation=form.is_simulation) # Assert pricePoint is valid. try: marketplace.get_price(pay_req['request']['pricePoint']) except UnknownPricePoint, exc: log.exception('calling get price_price()') return _error(request, exception=exc, is_simulation=form.is_simulation) # All validation passed, save state to the session. request.session['is_simulation'] = form.is_simulation request.session['notes'] = {'pay_request': pay_req, 'issuer_key': form.key} request.session['trans_id'] = 'webpay:%s' % uuid.uuid4() # Before we verify the user's PIN let's save some