def redirect_with_aktivitet_id(request, aktivitet_date_id, slug, date_implemented): """Requests to: /aktiviteter/123/foo/ are interpreted as a request to the old URL structure where only aktivitet date id was included as a parameter, and will be rewritten to: /aktiviteter/12/123/foo/ Assuming that the date exists, and its related aktivitet id is 12. Note that this redirect was implemented 2017-04-26. There are many references to the old URLs, in both online and printed forms, so this redirect will have to live on for a long time. """ librato.increment( 'sherpa.aktiviteter.show.old_url_redirect.%s' % date_implemented) try: aktivitet_date = AktivitetDate.objects.get(id=aktivitet_date_id) # Rebuild the path, inserting the aktivitet_id parameter if slug: postfix = '/%s/%s/' % (aktivitet_date_id, slug) else: postfix = '/%s/' % (aktivitet_date_id) prefix = request.path[: -(len(postfix) - 1)] destination = '%s%s%s' % (prefix, aktivitet_date.aktivitet.id, postfix) if request.META['QUERY_STRING']: destination = '%s?%s' % (destination, request.META['QUERY_STRING']) return redirect(destination, permanent=True) except AktivitetDate.DoesNotExist: raise Http404
def process_invoice(request): if 'enrollment' not in request.session: return redirect('enrollment:registration') enrollment = get_or_create_enrollment(request) if enrollment.state == 'registration': # Whoops, how did we get here without going through payment first? Redirect back. return redirect('enrollment:payment_method') elif enrollment.state == 'payment': # Cool, this is where we want to be. pass elif enrollment.state == 'complete': # Registration has already been completed, redirect forwards to results page return redirect('enrollment:result') for user in enrollment.users.all(): user.pending_user = User.create_pending_user(user.memberid) user.save() librato.increment('sherpa.medlemmer.innmeldinger') if enrollment.relation_type == 'family': librato.increment('sherpa.familiemedlemskap.innmelding.faktura_valgt') prepare_and_send_email(request, enrollment) enrollment.save_prices() enrollment.state = 'complete' enrollment.result = 'success_invoice' enrollment.save() return redirect('enrollment:result')
def membership_household_data(request): librato.increment('sherpa.api.oauth.membership_household.request') if not request.user.is_member(): # Not a member user_data = { 'hovedmedlem': get_member_data(request.user), 'husstandsmedlemmer': [], } elif not request.user.is_related_member(): # A main member user_data = { 'hovedmedlem': get_member_data(request.user), 'husstandsmedlemmer': [get_member_data(u) for u in request.user.get_children()], } else: # A household member if request.user.get_parent() is not None: user_data = { 'hovedmedlem': get_member_data(request.user.get_parent()), 'husstandsmedlemmer': [get_member_data(u) for u in request.user.get_parent().get_children()], } else: # A household member without a parent, send it as such user_data = { 'hovedmedlem': None, 'husstandsmedlemmer': [get_member_data(request.user)], } return HttpResponse(json.dumps(user_data))
def confirm_membership_by_token(request): """ Confirm the membership with only the given token as authentication. Note that the URL to this view is hardcoded in Focus which sends out emails/SMS with the URL and correct token. """ try: token = request.GET['code'] actor = Actor.objects.get(family_youth_member_accepted_token=token) youth_user = User.get_or_create_inactive(memberid=actor.memberid) context = { 'token': token, 'youth_user': youth_user, } except (KeyError, Actor.DoesNotExist): raise Http404 if request.method == 'GET': return render(request, 'common/user/membership_confirmation.html', context) elif request.method == 'POST': try: User.confirm_membership_by_token(token) librato.increment('sherpa.medlemmer.familiemedlemskap.bekreft_ungdomsmedlem') return redirect('%s?code=%s' % (reverse('user:confirm_membership_by_token'), token)) except: context['confirmation_error'] = True return render(request, 'common/user/membership_confirmation.html', context)
def convert_to_family_membership(request): try: request.user.convert_to_family_membership() librato.increment('sherpa.medlemmer.familiemedlemskap.konverter_husstand') except FocusServiceError: messages.error(request, 'focus_service_error') finally: return redirect('user:family')
def show(request, id): try: annonse = Annonse.objects.get(id=id, hidden=False) except Annonse.DoesNotExist: return render(request, 'central/fjelltreffen/show_not_found.html') context = {} if request.method == 'POST': form = ReplyForm(request.POST) if request.user.is_authenticated() else ReplyAnonForm(request.POST) if form.is_valid(): try: # Send the reply-email email_context = RequestContext(request, { 'annonse': annonse, 'reply': { 'name': form.cleaned_data['name'], 'email': form.cleaned_data['email'], 'text': form.cleaned_data['text'] } }) content = render_to_string('central/fjelltreffen/reply_email.txt', email_context) parse_for_spam(request, form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['text'], annonse) send_mail('DNT Fjelltreffen - Svar fra %s' % form.cleaned_data['name'], content, settings.DEFAULT_FROM_EMAIL, [annonse.email], fail_silently=False) librato.increment('sherpa.fjelltreffen_svar') request.session['fjelltreffen.reply'] = { 'name': form.cleaned_data['name'], 'email': form.cleaned_data['email'], 'text': form.cleaned_data['text'] } return redirect('fjelltreffen.views.show_reply_sent', annonse.id) except Exception: # Use both a message (for consistency with the report-failure) # and context to be able to manipulate the template based on message info messages.error(request, 'email_reply_failure') context.update({'email_reply_failure': True}) logger.warning(u"Klarte ikke å sende Fjelltreffen-epost", exc_info=sys.exc_info(), extra={'request': request} ) else: if request.user.is_authenticated(): form = ReplyForm(initial={ 'name': request.user.get_full_name(), 'email': request.user.get_email() }) else: form = ReplyAnonForm() report = '' if 'fjelltreffen.report' in request.session: report = request.session['fjelltreffen.report'] del request.session['fjelltreffen.report'] context.update({ 'annonse': annonse, 'form': form, 'report': report}) return render(request, 'central/fjelltreffen/show.html', context)
def process_request(self, request): ua_string = request.META.get('HTTP_USER_AGENT') if not ua_string: return if any([c.search(ua_string) for c in crawlers]): librato.increment('sherpa.backend.requests.crawler') else: librato.increment('sherpa.backend.requests.human')
def temporary_redirect(request, aktivitet_date_id, date_implemented): """ The URL path to the 'description' view was previously renamed. This view redirects requests to the old path to the new correct destination. """ # The date the redirect was implemented is included in the metric key. Check out the relevant metrics to see if the # old URLs are still in use before removing the redirect. librato.increment("sherpa.aktiviteter.show.old_url_redirect.%s" % date_implemented) return redirect("aktiviteter:description", aktivitet_date_id, permanent=True)
def confirm_membership(request): try: request.user.confirm_membership() librato.increment('sherpa.medlemmer.familiemedlemskap.bekreft_ungdomsmedlem') messages.info(request, 'membership_confirmed') except FocusServiceError: messages.error(request, 'focus_service_error') finally: return redirect('user:home')
def add_family_member(request): if request.method != 'POST' \ or 'memberid' not in request.POST \ or 'country' not in request.POST \ or (request.POST['country'] == 'NO' and 'zipcode' not in request.POST): return redirect('user:family') try: # Include pending users in order to give an explicit error message new_family_member = User.get_users(include_pending=True).get(memberid=request.POST['memberid']) except (User.DoesNotExist, ValueError): messages.error(request, 'user_does_not_exist') return redirect('user:family') if not new_family_member.is_member(): messages.error(request, 'user_is_not_member') return redirect('user:family') if new_family_member.address.country.code != request.POST['country']: messages.error(request, 'invalid_address') return redirect('user:family') if new_family_member.address.country.code == 'NO' \ and new_family_member.address.zipcode.zipcode != request.POST['zipcode']: messages.error(request, 'invalid_address') return redirect('user:family') if new_family_member.is_pending: messages.error(request, 'user_is_pending') return redirect('user:family') if new_family_member == request.user: messages.error(request, 'user_is_current_user') return redirect('user:family') if new_family_member.has_family(): messages.error(request, 'user_has_family') return redirect('user:family') if new_family_member.is_lifelong_member(): messages.error(request, 'user_is_lifelong_member') return redirect('user:family') if new_family_member.get_dnt_age() >= settings.MEMBERSHIP['AGES']['MAIN'] \ and request.user.family.has_max_adult_members(): messages.error(request, 'user_is_adult_and_max_adults_reached') return redirect('user:family') assert request.user.has_family(), "User without family (single or not) should not be able to add family members" try: request.user.family.add_family_member(new_family_member) librato.increment('sherpa.medlemmer.familiemedlemskap.legg_til.eksisterende') except FocusServiceError: messages.error(request, 'focus_service_error') finally: return redirect('user:family')
def url_versioning(request, resource, version, require_authentication=True): try: if require_authentication and not authenticate(request): raise invalid_authentication_exception() format = requested_representation_from_url(request) librato.increment('sherpa.api.tailored.url_versioning') librato.increment('sherpa.api.tailored.version.v%s' % version) return call_api(request, resource, version, format) except BadRequest as e: return e.response()
def get(code): """Lookup and create the aktivitet with the given turkode in Montis' API""" librato.increment('sherpa.requests.montis') try: r = requests.get( "%s/%s/" % (settings.DNTOSLO_MONTIS_API_URL, code), params={ 'client': 'dnt', 'autentisering': settings.DNTOSLO_MONTIS_API_KEY, }, ) except (requests.ConnectionError, requests.exceptions.SSLError): raise MontisDateUnretrievable if r.status_code == 404: raise MontisDateNotFound if r.status_code != 200: logger.warning( "Montis API didn't return a valid HTTP response", extra={ 'code': code, 'response': r, 'body': r.text, 'http_status_code': r.status_code, } ) raise MontisDateInvalid try: return Aktivitet( code=code, dates=[ AktivitetDate(**AktivitetDate.map_fields(json_date)) for json_date in r.json() ], ) except KeyError: # May occur if the corresponding Montis date doesn't send all the expected fields logger.warning( "Montis API returned invalid data", exc_info=sys.exc_info(), extra={ 'code': code, 'response': r, 'body': r.text, 'http_status_code': r.status_code, } ) raise MontisDateInvalid
def header_versioning(request, versions, require_authentication=True): try: if require_authentication and not authenticate(request): raise invalid_authentication_exception() version, format = requested_representation_from_header(request) try: resource = [v for v in versions if v['version'] == version][0]['resource'] except IndexError: return invalid_version_response(version) librato.increment('sherpa.api.tailored.header_versioning') librato.increment('sherpa.api.tailored.version.%s' % version) return call_api(request, resource, version, format) except BadRequest as e: return e.response()
def confirm_family_member_enrollment(request): if 'user.family.validated_user' not in request.session: return redirect('user:family') del request.session['user.family.enrollment_form'] new_family_member = request.session.pop('user.family.validated_user') new_family_member['dob'] = datetime.strptime(new_family_member['dob'], "%Y-%m-%d").date() assert request.user.has_family(), "User without family (single or not) should not be able to enroll family members" try: request.user.family.enroll_family_member(new_family_member) librato.increment('sherpa.medlemmer.familiemedlemskap.legg_til.nytt_medlem') except FocusServiceError: messages.error(request, 'focus_service_error') finally: return redirect('user:family')
def forening(request, version, format): if request.method == 'GET': require_focus(request) librato.increment('sherpa.api.tailored.forening.request') if 'bruker_sherpa_id' in request.GET or 'bruker_medlemsnummer' in request.GET: try: # Lookup by specified members' access if 'bruker_sherpa_id' in request.GET and 'bruker_medlemsnummer' in request.GET: user = User.get_users(include_pending=True).get(id=request.GET['bruker_sherpa_id'], memberid=request.GET['bruker_medlemsnummer']) elif 'bruker_sherpa_id' in request.GET: user = User.get_users(include_pending=True).get(id=request.GET['bruker_sherpa_id']) elif 'bruker_medlemsnummer' in request.GET: try: user = User.get_or_create_inactive(memberid=request.GET['bruker_medlemsnummer']) except (User.DoesNotExist, ValueError): # No such member raise User.DoesNotExist foreninger = [get_forening_data(f) for f in user.all_foreninger()] librato.increment('sherpa.api.tailored.forening.response.200') return HttpResponse(json.dumps(foreninger)) except (User.DoesNotExist, ValueError): librato.increment('sherpa.api.tailored.forening.response.404') raise BadRequest( "A member matching that 'sherpa_id', 'bruker_medlemsnummer', or both if both were provided, does not exist.", code=error_codes.RESOURCE_NOT_FOUND, http_code=404 ) else: librato.increment('sherpa.api.tailored.forening.response.400') raise BadRequest( "You must supply either a 'bruker_sherpa_id' or 'bruker_medlemsnummer' parameter for forening lookup by member. Only this form of forening-lookup is implemented in this version.", code=error_codes.MISSING_REQUIRED_PARAMETER, http_code=400 ) else: librato.increment('sherpa.api.tailored.forening.response.400') raise BadRequest( "Unsupported HTTP verb", code=error_codes.UNSUPPORTED_HTTP_VERB, http_code=400 )
def temporary_redirect(request, aktivitet_date_id, date_implemented): """ The URL path to the 'description' view was previously renamed. This view redirects requests to the old path to the new correct destination. """ # The date the redirect was implemented is included in the metric key. # Check out the relevant metrics to see if the old URLs are still in use # before removing the redirect. try: aktivitet_date = AktivitetDate.objects.select_related('aktivitet').get( id=aktivitet_date_id) librato.increment( 'sherpa.aktiviteter.show.old_url_redirect.%s' % date_implemented) return redirect( 'aktiviteter:description', aktivitet_date.aktivitet.id, aktivitet_date_id, permanent=True) except: raise Http404
def send_sms(number, message, logging_extra={}): """ Send an SMS message to the given number. Raises SMSGatewayDeliveryError if the SMS message couldn't be delivered through the SMS gateway for any reason. The logging_extra parameter may be filled with extra logging data on failure """ logging_extra["number"] = number logging_extra["sms_message"] = message try: librato.increment("sherpa.requests.sms") r = requests.get(settings.SMS_URL % (quote_plus(number), quote_plus(message.encode("utf-8")))) if r.text.find("1 SMS messages added to queue") == -1: logging_extra["request_object"] = r logging_extra["response_text"] = r.text logger.error("Fikk ikke sendt SMS: Ukjent status-svar fra SMS-gateway", extra=logging_extra) raise SMSGatewayDeliveryError("Unknown response status") except requests.ConnectionError: logger.error( "Fikk ikke sendt SMS: Kan ikke koble til SMS-gateway", exc_info=sys.exc_info(), extra=logging_extra ) raise SMSGatewayDeliveryError("Connection error")
def members(request, version, format): if request.method == 'GET': require_focus(request) librato.increment('sherpa.api.tailored.medlem.request') try: if 'sherpa_id' in request.GET and 'medlemsnummer' in request.GET: user = User.get_users(include_pending=True).get(id=request.GET['sherpa_id'], memberid=request.GET['medlemsnummer']) elif 'sherpa_id' in request.GET: user = User.get_users(include_pending=True).get(id=request.GET['sherpa_id']) elif 'medlemsnummer' in request.GET: try: user = User.get_or_create_inactive(memberid=request.GET['medlemsnummer']) except (User.DoesNotExist, ValueError): # No such member raise User.DoesNotExist else: librato.increment('sherpa.api.tailored.medlem.response.400') raise BadRequest( "You must supply either an 'sherpa_id' or 'medlemsnummer' parameter for member lookup", code=error_codes.MISSING_REQUIRED_PARAMETER, http_code=400 ) librato.increment('sherpa.api.tailored.medlem.response.200') return HttpResponse(json.dumps(get_member_data(user))) except (User.DoesNotExist, ValueError): librato.increment('sherpa.api.tailored.medlem.response.404') raise BadRequest( "A member matching that 'sherpa_id', 'medlemsnummer', or both if both were provided, does not exist.", code=error_codes.RESOURCE_NOT_FOUND, http_code=404 ) else: librato.increment('sherpa.api.tailored.medlem.response.400') raise BadRequest( "Unsupported HTTP verb", code=error_codes.UNSUPPORTED_HTTP_VERB, http_code=400 )
def membership_data(request): librato.increment('sherpa.api.oauth.membership.request') try: token = request.META['HTTP_AUTHORIZATION'].replace('Bearer ', '') at = AccessToken.objects.select_related('application').get(token=token) client_id = at.application.id client_name = at.application.name request.user.last_active_oauth_date = datetime.now() request.user.save() log, created = UserOauthActiveLog.objects.get_or_create( user=request.user, oauth_client_id=client_id, defaults={ 'last_data_date': request.user.last_active_oauth_date, }) if not created: log.last_data_date = request.user.last_active_oauth_date log.save() except Exception as e: pass return HttpResponse(json.dumps(get_member_data(request.user)))
def membership_fee(request, memberid): librato.increment('sherpa.api.tailored.medlemskontingent.request') try: user = User.get_or_create_inactive(memberid) response = json.dumps({ 'id': user.id, 'hasPaid': user.payment.status['is_paid'], }) librato.increment('sherpa.api.tailored.medlemskontingent.response.200') return HttpResponse(response, content_type="application/json") except (User.DoesNotExist, ValueError): librato.increment('sherpa.api.tailored.medlemskontingent.response.404') raise Http404
def membership_data(request): librato.increment('sherpa.api.oauth.membership.request') return HttpResponse(json.dumps(get_member_data(request.user)))
def process_card(request): if 'enrollment' not in request.session: return redirect('enrollment:registration') enrollment = get_or_create_enrollment(request) if enrollment.state == 'registration': # Whoops, how did we get here without going through payment first? Redirect back. # Note, *this* makes it impossible to use a previously verified transaction id # on a *second* registration by skipping the payment view and going straight to this check. return redirect('enrollment:payment_method') elif enrollment.state == 'payment': # Cool, this is where we want to be. pass elif enrollment.state == 'complete': # Registration has already been completed, redirect forwards to results page return redirect('enrollment:result') # The client's transaction id CAN differ from the one we think is active. Let them override it, # given that the transaction id is already registered. Note that the transaction id from the # GET parameter is obviously untrusted input. try: enrollment.transactions.update(active=False) active_transaction = enrollment.transactions.get(transaction_id=request.GET['transactionId']) active_transaction.active = True active_transaction.save() except Transaction.DoesNotExist: # They returned with a transaction id which we haven't registered on them - cannot see this happen # without them tampering with the GET parameter, we'll have to send them back with an error message. messages.error(request, 'invalid_transaction_id') enrollment.state = 'payment' enrollment.save() return redirect('enrollment:payment_method') if request.GET.get('responseCode') == 'OK': try: librato.increment('sherpa.requests.nets.process') r = requests.get(settings.NETS_PROCESS_URL, params={ 'merchantId': settings.NETS_MERCHANT_ID, 'token': settings.NETS_TOKEN, 'operation': 'SALE', 'transactionId': active_transaction.transaction_id }) response = r.text.encode('utf-8') dom = ET.fromstring(response) response_code = dom.find(".//ResponseCode") response_text = dom.find(".//ResponseText") payment_verified = False tx_already_processed_explicit = response_code.text == '98' tx_already_processed_general = ( response_code.text == '99' and response_text is not None and response_text.text == 'Transaction already processed' ) if response_code is None: # Crap, we didn't get the expected response from Nets. # This has happened a few times before. We'll have to handle it ourselves. logger.error( "Mangler 'ResponseCode' element fra Nets", extra={ 'request': request, 'nets_response': response, 'enrollment': enrollment, 'transaction_id': active_transaction.transaction_id } ) enrollment.state = 'payment' enrollment.save() context = current_template_layout(request) return render(request, 'central/enrollment/payment-process-error.html', context) elif tx_already_processed_explicit or tx_already_processed_general: # The transaction might have already been processed if the user resends the process_card # request - recheck nets with a Query request and verify those details sale_response = response librato.increment('sherpa.requests.nets.query') r = requests.get(settings.NETS_QUERY_URL, params={ 'merchantId': settings.NETS_MERCHANT_ID, 'token': settings.NETS_TOKEN, 'transactionId': active_transaction.transaction_id }) response = r.text.encode('utf-8') dom = ET.fromstring(response) order_amount = int(dom.find(".//OrderInformation/Amount").text) captured_amount = int(dom.find(".//Summary/AmountCaptured").text) credited_amount = int(dom.find(".//Summary/AmountCredited").text) if order_amount == (captured_amount - credited_amount) == enrollment.total_price() * 100: payment_verified = True else: logger.warning( "Nets: Prosessert transaksjon matcher ikke forventet beløp", extra={ 'request': request, 'enrollment': enrollment, 'nets_sale_response': sale_response, 'nets_query_response': response, 'transaction_id': active_transaction.transaction_id, 'payment_verified': payment_verified, 'order_amount': order_amount, 'captured_amount': captured_amount, 'credited_amount': credited_amount, 'total_price_100': enrollment.total_price() * 100 } ) elif response_code.text == 'OK': payment_verified = True if payment_verified: # Mark the transaction as successful active_transaction.state = 'success' active_transaction.save() # Register the payment in focus for user in enrollment.users.all(): focus_user = FocusEnrollment.objects.get(memberid=user.memberid) focus_user.paid = True focus_user.save() user.pending_user = User.create_pending_user(user.memberid) user.save() librato.increment('sherpa.medlemmer.innmeldinger') if enrollment.relation_type == 'family': librato.increment('sherpa.familiemedlemskap.innmelding.kort_betalt') prepare_and_send_email(request, enrollment) enrollment.save_prices() enrollment.state = 'complete' enrollment.result = 'success_card' enrollment.save() else: active_transaction.state = 'fail' active_transaction.save() enrollment.state = 'registration' enrollment.result = 'fail' enrollment.save() except requests.ConnectionError: logger.warning( "Nets `process` feil", exc_info=sys.exc_info(), extra={'request': request} ) enrollment.state = 'payment' enrollment.save() context = current_template_layout(request) return render(request, 'central/enrollment/payment-process-error.html', context) else: active_transaction.state = 'cancel' active_transaction.save() enrollment.state = 'registration' enrollment.result = 'cancel' enrollment.save() return redirect('enrollment:result')
def payment(request): enrollment = get_or_create_enrollment(request) if enrollment.state == 'registration': # All right, enter payment state enrollment.state = 'payment' enrollment.save() elif enrollment.state == 'payment': # Already in payment state, redirect them forwards to processing if enrollment.payment_method == 'invoice': return redirect('enrollment:process_invoice') elif enrollment.payment_method == 'card': # Let's check for an existing transaction first try: active_transaction = enrollment.transactions.get(state='register', active=True) # Yeah, it's there. Skip payment and redirect forwards to processing return redirect("%s?merchantId=%s&transactionId=%s" % ( settings.NETS_TERMINAL_URL, settings.NETS_MERCHANT_ID, active_transaction.transaction_id )) except Transaction.DoesNotExist: # No active transactions - maybe a problem occured during payment. # Assume payment failed and just redo it - if something failed, we'll know # through logs and hopefully discover any double-payments pass elif enrollment.state == 'complete': # Registration has already been completed, redirect forwards to results page return redirect('enrollment:result') enrollment.payment_method = request.POST.get('payment_method', '') # Validate chosen payment method if enrollment.payment_method not in ['card', 'invoice']: messages.error(request, 'invalid_payment_method') return redirect('enrollment:payment_method') # Ensure card payment is accepted if chosen if enrollment.payment_method == 'card' and not Settings.get_cached().enrollment_accept_card: messages.error(request, 'invalid_payment_method') return redirect('enrollment:payment_method') # Ensure invoice is accepted if chosen if enrollment.payment_method == 'invoice' and not Settings.get_cached().enrollment_accept_invoice: messages.error(request, 'invalid_payment_method') return redirect('enrollment:payment_method') # Ensure user is not enrolling through aktivitet if invoice is chosen if enrollment.payment_method == 'invoice' and 'innmelding.aktivitet' in request.session: messages.error(request, 'invalid_payment_method') return redirect('enrollment:payment_method') # Ok, we're good to go. Save all users to Focus enrollment.save() enrollment.save_users_to_focus() # If we're paying by invoice, skip ahead to invoice processing if enrollment.payment_method == 'invoice': return redirect('enrollment:process_invoice') # Paying with card, move on. order_number = Transaction.generate_order_number() # Choose a user as the Nets customer; preferably the main member try: nets_customer = enrollment.get_chosen_main_member() except EnrollmentUser.DoesNotExist: # There's no main member, so they're either all children or related to an existing member. We still need a # 'main' user though, for the customer data. Try to find the oldest one that *has* contact information. nets_customer = enrollment.users.exclude(email='').order_by('dob')[0] first_name, last_name = nets_customer.name.rsplit(maxsplit=1) description = render_to_string('central/enrollment/payment-terminal.html', request=request) # Send the transaction registration to Nets try: librato.increment('sherpa.requests.nets.register') r = requests.get(settings.NETS_REGISTER_URL, params={ 'merchantId': settings.NETS_MERCHANT_ID, 'token': settings.NETS_TOKEN, 'orderNumber': order_number, 'customerFirstName': first_name, 'customerLastName': last_name, 'customerEmail': nets_customer.email, 'currencyCode': 'NOK', 'amount': enrollment.total_price() * 100, 'orderDescription': description, 'redirectUrl': "http://%s%s" % (request.site.domain, reverse("enrollment:process_card")) }) # Sweet, almost done, now just send the user to complete the transaction # Consider handling errors here (unexpected XML response or connection error) # We recieved a random "Unable to create setup string" message once, ignoring it for now response = r.text.encode('utf-8') enrollment.transactions.update(active=False) transaction = Transaction( enrollment=enrollment, transaction_id=ET.fromstring(response).find("TransactionId").text, order_number=order_number, state='register', active=True, ) transaction.save() except Exception as e: # Handle any exception that might occur (requests.ConnectionError, invalid response from Nets, etc.) logger.warning( "Nets `register` feil", exc_info=sys.exc_info(), extra={'request': request} ) messages.error(request, 'nets_register_connection_error') return redirect('enrollment:payment_method') return redirect("%s?merchantId=%s&transactionId=%s" % ( settings.NETS_TERMINAL_URL, settings.NETS_MERCHANT_ID, transaction.transaction_id ))
def set_main_member(request): enrollment = get_or_create_enrollment(request) if enrollment.state == 'payment': # Payment has been initiated but the user goes back here - why? # Reset the state and let them reinitiate payment when they're ready. enrollment.state = 'registration' enrollment.save() elif enrollment.state == 'complete': # A previous registration has been completed, so why would the user come directly here? # Just redirect them back to registration which will restart a new registration. return redirect("enrollment:registration") if request.method != 'POST': return redirect("enrollment:verification") # Assign the chosen relation type; default to 'household' relation_type = request.POST.get('relation-type', 'household') if relation_type not in ['family', 'household']: raise Exception("Invalid membership relation type '%s' POSTed" % relation_type) if relation_type == 'family' and not enrollment.eligible_for_family_membership(): logger.warning( "Enrolling member was able to choose family membership even though not eligible", extra={ 'request': request, 'enrollment': enrollment, } ) messages.error(request, 'not_eligible_for_family_membership') return redirect('enrollment:verification') if relation_type == 'family' and not enrollment.forening.offers_family_membership: logger.warning( "Enrolling member was able to choose family membership even though their forening doesn't offer it", extra={ 'request': request, 'enrollment': enrollment, } ) return redirect('enrollment:verification') enrollment.relation_type = relation_type enrollment.save() # Assign the chosen main member enrollment.users.all().update(chosen_main_member=False) if request.POST.get('main', '') != '': user = enrollment.users.get(id=request.POST['main']) if not user.can_be_main_member(): messages.error(request, 'invalid_main_member') return redirect('enrollment:verification') user.chosen_main_member = True user.save() else: # No choice for main member was made, which might be OK; check if enrollment.existing_memberid != '': # There's a relation to an existing member; all right, carry on pass elif not enrollment.has_potential_main_member(): # There are only children in this enrollment, no one can be a main member; all right, carry on pass elif not enrollment.has_multiple_potential_main_members(): # Okay, there's only one potential main member. We did expect their ID to be POSTed by a hidden input, # but no worries; we can deduce who it should be in hindsight. Delegate the logic to the model. enrollment.set_single_main_member() else: # No existing member AND there are multiple potential main members: This shouldn't have happened, might be # a UI bug logger.warning( "More than one available main members and no choice made. Fix the UI", extra={ 'request': request, 'enrollment': enrollment, } ) messages.error(request, 'no_main_member') return redirect('enrollment:verification') if enrollment.relation_type == 'family': librato.increment('sherpa.familiemedlemskap.innmelding.startet') # Successfully set main member; redirect forwards return redirect('enrollment:payment_method')
def membership(request, version, format): if request.method == 'GET': require_focus(request) librato.increment('sherpa.api.tailored.medlemskap.request') if not 'medlemsnummer' in request.GET or not 'født' in request.GET: librato.increment('sherpa.api.tailored.medlemskap.response.400') raise BadRequest( "Missing 'medlemsnummer' and/or 'født' parameters'", code=error_codes.MISSING_REQUIRED_PARAMETER, http_code=400 ) try: requested_date_of_birth = datetime.strptime(request.GET['født'], "%d.%m.%Y").date() except ValueError: librato.increment('sherpa.api.tailored.medlemskap.response.400') raise BadRequest( "Could not parse the 'født' parameter ('%s'), which should be in the following format: 'dd.mm.yyyy'" % request.GET['født'], code=error_codes.MISSING_REQUIRED_PARAMETER, http_code=400 ) try: try: user = User.get_or_create_inactive(memberid=request.GET['medlemsnummer']) except (User.DoesNotExist, ValueError): # No such member raise User.DoesNotExist # Make sure we have the most up-to-date information; users will often contact membership service and # they'll fix their birth date directly in Focus, and then retry some service using this API resource user.clear_cache() # Verify the requested date of birth if user.get_birth_date() != requested_date_of_birth: raise User.DoesNotExist if 'hele_husstanden' in request.GET: if not user.is_related_member(): user_data = { 'hovedmedlem': get_member_data(user), 'husstandsmedlemmer': [get_member_data(u) for u in user.get_children()], } else: if user.get_parent() is not None: user_data = { 'hovedmedlem': get_member_data(user.get_parent()), 'husstandsmedlemmer': [get_member_data(u) for u in user.get_parent().get_children()], } else: # A household member without a parent, send it as such user_data = { 'hovedmedlem': None, 'husstandsmedlemmer': [get_member_data(user)], } else: user_data = get_member_data(user) librato.increment('sherpa.api.tailored.medlemskap.response.200') return HttpResponse(json.dumps(user_data)) except (User.DoesNotExist, ValueError): librato.increment('sherpa.api.tailored.medlemskap.response.404') raise BadRequest( "A membership with member ID '%s' and date of birth '%s' does not exist." % (request.GET['medlemsnummer'], request.GET['født']), code=error_codes.RESOURCE_NOT_FOUND, http_code=404 ) else: librato.increment('sherpa.api.tailored.medlemskap.response.400') raise BadRequest( "Unsupported HTTP verb", code=error_codes.UNSUPPORTED_HTTP_VERB, http_code=400 )
def prices(request, version, format): def format_prices(forening, lang): return { 'overnatting': [{ 'id': lodging.id, 'navn': lodging.name_eng if lang == 'en' else lodging.name, 'pris_medlem': lodging.price_member, 'pris_ikkemedlem': lodging.price_nonmember, } for lodging in forening.lodging_prices.all()], 'proviant': [{ supply_category.name_eng if lang == 'en' else supply_category.name: [{ 'id': supply.id, 'navn': supply.name_eng if lang == 'en' else supply.name, 'pris_medlem': supply.price_member, 'pris_ikkemedlem': supply.price_nonmember, } for supply in supply_category.supplies.all()] } for supply_category in forening.supply_categories.all()] } librato.increment('sherpa.api.tailored.priser.request') if request.method != 'GET': librato.increment('sherpa.api.tailored.priser.response.400') raise BadRequest( "Unsupported HTTP verb '%s'" % request.method, code=error_codes.UNSUPPORTED_HTTP_VERB, http_code=400, ) if request.GET.get('språk', 'nb').lower().startswith('en'): lang = 'en' else: lang = 'nb' if 'forening' in request.GET: try: forening = Forening.objects.get(turbasen_object_id=request.GET['forening']) return HttpResponse(json.dumps(format_prices(forening, lang))) except Forening.DoesNotExist: librato.increment('sherpa.api.tailored.priser.response.404') raise BadRequest( "A forening with object id '%s', does not exist." % request.GET['forening'], code=error_codes.RESOURCE_NOT_FOUND, http_code=404, ) elif 'hytte' in request.GET: try: sted = Sted.get(request.GET['hytte']) # @TODO: Use private fields to get the appropriate owner: first forening of privat.juridisk_eier, # privat.vedlikeholdes_av forening = Forening.objects.get(turbasen_object_id=sted['grupper'][0]) librato.increment('sherpa.api.tailored.priser.response.200') return HttpResponse(json.dumps(format_prices(forening, lang))) except DocumentNotFound: librato.increment('sherpa.api.tailored.priser.response.404') raise BadRequest( "A cabin with object id '%s', does not exist." % request.GET['hytte'], code=error_codes.RESOURCE_NOT_FOUND, http_code=404, ) else: librato.increment('sherpa.api.tailored.priser.response.200') return HttpResponse(json.dumps([{ 'object_id': forening.turbasen_object_id, 'navn': forening.name, 'priser': format_prices(forening, lang), } for forening in Forening.objects.filter(type='forening')]))
def memberid(request, version, format): librato.increment('sherpa.api.tailored.medlemsnummer.request') if request.method != 'GET': librato.increment('sherpa.api.tailored.medlemsnummer.response.400') raise BadRequest( "Unsupported HTTP verb '%s'" % request.method, code=error_codes.UNSUPPORTED_HTTP_VERB, http_code=400 ) require_focus(request) if 'mobilnummer' not in request.GET: librato.increment('sherpa.api.tailored.medlemsnummer.response.400') raise BadRequest( "Missing required 'mobilnummer' parameter", code=error_codes.MISSING_REQUIRED_PARAMETER, http_code=400 ) phone_number = request.GET['mobilnummer'].strip() users = lookup_users_by_phone(phone_number) # Send the recipient an SMS if len(users) == 0: librato.increment('sherpa.api.tailored.medlemsnummer.response.404') raise BadRequest( "A member with phone number '%s' wasn't found." % phone_number, code=error_codes.RESOURCE_NOT_FOUND, http_code=404 ) elif len(users) == 1: user = users[0] elif len(users) > 1: # Usually, this will be because household members have the same number as their parents. # Check if any of these are related, and in that case, use the parent. user = None for user_to_check in users: if user_to_check.is_related_member() and \ user_to_check.get_parent() is not None and \ user_to_check.get_parent() in users: # Ah, this parent is in the result set - probably the one we want, use it user = user_to_check.get_parent() break if user is None: # Multiple hits, and they are not related. What do? Pick a random hit for now. user = users[0] # Delete the user cache in case the number was recently updated; the cache may differ from our raw lookup above user.clear_cache() result = send_sms_receipt(request, user) if result['status'] == 'ok': librato.increment('sherpa.api.tailored.medlemsnummer.response.200') return HttpResponse(json.dumps({ 'status': 'ok', 'message': 'An SMS was successfully sent to the member with the given phone number.', })) elif result['status'] == 'service_fail': librato.increment('sherpa.api.tailored.medlemsnummer.response.500') raise BadRequest( "There is a problem with our SMS gateway and we were unable to send the SMS.", code=error_codes.SMS_GATEWAY_ERROR, http_code=500 ) else: # Might happen if we add a new status code to the send_sms_receipt function and forget to account for it here logger.error( "Unknown SMS return status code '%s'" % result['status'], extra={'request': request} ) librato.increment('sherpa.api.tailored.medlemsnummer.response.500') raise BadRequest( "An internal error occurred while trying to send the SMS. This error has been logged and we'll get it fixed asap.", code=error_codes.INTERNAL_ERROR, http_code=500 )
def index(request): turledere = cache.get('admin.turleder_count') if turledere is None: turledere = Turleder.objects.only( # Select only the related approved forening, and only the ID from that model 'forening_approved', 'forening_approved__id', ).select_related( # Join the related forening into this query as we'll traverse that later 'forening_approved', ).distinct( # The Turleder model may have >1 references to a user, so select distinctly on user 'user', ) # Make sure the lazy queryset has been evaluated before caching it len(turledere) cache.set('admin.turleder_count', turledere, 60 * 60 * 24 * 14) turleder_stats = { 'total': len(turledere), # Filter on the local forening in code - it's prefetched, so that's much faster, and it lets us cache the # entire query instead of having a seperate cache key per forening 'local': len([t for t in turledere if t.forening_approved == request.active_forening]), } aktiviteter = cache.get('admin.aktivitet_count.%s' % request.active_forening.id) if aktiviteter is None: aktiviteter = AktivitetDate.get_searchable().filter( Q(aktivitet__organizer_forening=request.active_forening) | Q(aktivitet__co_organizers_forening=request.active_forening), start_date__gte=date.today(), ).count() cache.set('admin.aktivitet_count', aktiviteter, 60 * 60 * 6) dashboard_stats = { 'turledere': turleder_stats, 'aktiviteter': aktiviteter, } betablog = cache.get('admin.betablog') BETABLOG_ITEM_COUNT = 4 if betablog is None: try: betablog = [] librato.increment('sherpa.requests.betablog') r = requests.get("http://beta.dnt.no/", params={'feed': 'rss2'}) channel = ET.fromstring(r.content).find('channel') for item in channel.findall('item')[:BETABLOG_ITEM_COUNT]: content = item.find('description').text image = None m = re.search('<img.*?src="(.*?)" ', content) if m is not None: image = m.group(1) pub_date = datetime.strptime(item.find('pubDate').text[:-6], "%a, %d %b %Y %H:%M:%S") betablog.append({ 'title': item.find('title').text, 'link': item.find('link').text, 'content': content, 'image': image, 'pub_date': pub_date, 'is_new': pub_date > datetime.now() - timedelta(days=7), }) except: logger.warning( "Kunne ikke hente innhold fra betabloggen", exc_info=sys.exc_info(), extra={'request': request} ) cache.set('admin.betablog', betablog, 60 * 60 * 12) context = { 'betablog': betablog, 'dashboard_stats': dashboard_stats, } return render(request, 'central/admin/dashboard.html', context)
def membership_price(request, version, format): if request.method == 'GET': require_focus(request) librato.increment('sherpa.api.tailored.medlemskapspris.request') if not 'postnummer' in request.GET: librato.increment('sherpa.api.tailored.medlemskapspris.response.400') raise BadRequest( "Missing required 'postnummer' parameter", code=error_codes.MISSING_REQUIRED_PARAMETER, http_code=400 ) try: # Get focus zipcode-forening ID focus_forening_id = cache.get('focus.zipcode_forening.%s' % request.GET['postnummer']) if focus_forening_id is None: focus_forening_id = FocusZipcode.objects.get(zipcode=request.GET['postnummer']).main_forening_id cache.set('focus.zipcode_forening.%s' % request.GET['postnummer'], focus_forening_id, 60 * 60 * 24 * 7) # Get forening based on zipcode-ID forening = Forening.objects.get(focus_id=focus_forening_id) price = forening.get_focus_price() # Success, return the appropriate data librato.increment('sherpa.api.tailored.medlemskapspris.response.200') return HttpResponse(json.dumps({ 'forening': {'sherpa_id': forening.id, 'navn': forening.name}, 'pristabell': { 'main': { 'navn': str(get_membership_type_by_codename('main')['name']), 'pris': price.main, }, 'youth': { 'navn': str(get_membership_type_by_codename('youth')['name']), 'pris': price.youth, }, 'senior': { 'navn': str(get_membership_type_by_codename('senior')['name']), 'pris': price.senior, }, 'lifelong': { 'navn': str(get_membership_type_by_codename('lifelong')['name']), 'pris': price.lifelong, }, 'child': { 'navn': str(get_membership_type_by_codename('child')['name']), 'pris': price.child, }, 'school': { 'navn': str(get_membership_type_by_codename('school')['name']), 'pris': price.school, }, 'household': { 'navn': str(get_membership_type_by_codename('household')['name']), 'pris': price.household, }, } })) except FocusZipcode.DoesNotExist: # The Zipcode doesn't exist in Focus, but if it exists in our Zipcode model, Focus is just not updated if Zipcode.objects.filter(zipcode=request.GET['postnummer']).exists(): logger.warning( "Postnummer finnes i Zipcode, men ikke i Focus!", exc_info=sys.exc_info(), extra={ 'request': request, 'postnummer': request.GET['postnummer'] } ) librato.increment('sherpa.api.tailored.medlemskapspris.response.404') raise BadRequest( "The postal code '%s' exists, but isn't connected to a Forening. It should be, and we've logged this occurrence." % request.GET['postnummer'], code=error_codes.RESOURCE_NOT_FOUND, http_code=404 ) else: # This *could* be an entirely new Zipcode, or just an invalid one. librato.increment('sherpa.api.tailored.medlemskapspris.response.404') raise BadRequest( "The postal code '%s' isn't registered in our database." % request.GET['postnummer'], code=error_codes.RESOURCE_NOT_FOUND, http_code=404 ) except Forening.DoesNotExist: logger.warning( "Focus-postnummer mangler foreningstilknytning!", exc_info=sys.exc_info(), extra={'request': request} ) librato.increment('sherpa.api.tailored.medlemskapspris.response.404') raise BadRequest( "The postal code '%s' exists, but isn't connected to a Forening. It should be, and we've logged this occurrence." % request.GET['postnummer'], code=error_codes.RESOURCE_NOT_FOUND, http_code=404 ) else: librato.increment('sherpa.api.tailored.medlemskapspris.response.400') raise BadRequest( "Unsupported HTTP verb", code=error_codes.UNSUPPORTED_HTTP_VERB, http_code=400 )
def show(request, id): try: annonse = Annonse.objects.get(id=id, hidden=False) except Annonse.DoesNotExist: return render(request, 'central/fjelltreffen/show_not_found.html') context = {} if request.method == 'POST': form = ReplyForm(request.POST) if request.user.is_authenticated() else ReplyAnonForm(request.POST) if form.is_valid(): parse_for_spam( request, form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['text'], annonse, ) try: email_context = { 'annonse': annonse, 'sender': { 'name': form.cleaned_data['name'], 'email': form.cleaned_data['email'], 'text': form.cleaned_data['text'] } } # Send the reply email to the advertiser content = render_to_string('central/fjelltreffen/reply_email.txt', email_context, request=request) send_mail( 'DNT Fjelltreffen - Svar fra %s' % form.cleaned_data['name'], content, settings.DEFAULT_FROM_EMAIL, [annonse.email], fail_silently=False, ) # At this point, the reply email was successful, so send a confirmation copy to the sender try: content = render_to_string( 'central/fjelltreffen/reply_copy_email.txt', email_context, request=request, ) send_mail( 'DNT Fjelltreffen - Kopi av ditt svar', content, settings.DEFAULT_FROM_EMAIL, [form.cleaned_data['email']], fail_silently=False, ) except: request.session['fjelltreffen.reply.email_copy_failure'] = True librato.increment('sherpa.fjelltreffen_svar') request.session['fjelltreffen.reply'] = { 'name': form.cleaned_data['name'], 'email': form.cleaned_data['email'], 'text': form.cleaned_data['text'] } return redirect('fjelltreffen:show_reply_sent', annonse.id) except: context['email_reply_failure'] = True logger.warning( "Klarte ikke å sende Fjelltreffen-epost", exc_info=sys.exc_info(), extra={'request': request} ) else: if request.user.is_authenticated(): form = ReplyForm(initial={ 'name': request.user.get_full_name(), 'email': request.user.get_email() }) else: form = ReplyAnonForm() report = '' if 'fjelltreffen.report' in request.session: report = request.session['fjelltreffen.report'] del request.session['fjelltreffen.report'] context.update({ 'annonse': annonse, 'form': form, 'report': report}) return render(request, 'central/fjelltreffen/show.html', context)