def post(self, request): phone_number = str(self.request.data.get('phone_number', '')).strip() users = lookup_users_by_phone(phone_number) users += self.lookup_local_users_by_phone(phone_number) if not len(users): return Response({'error': 'not found'}, status=403) SMSAuthCode.objects.filter(phone_number=phone_number).delete() auth_code = SMSAuthCode.generate_code() salt = crypto.get_random_string() iterations = randint(10000, 10100) encrypted_code = crypto.pbkdf2(auth_code, salt, iterations) code = SMSAuthCode.objects.create( phone_number=phone_number, code=encrypted_code, salt=salt, iterations=iterations ) for user in users: code.users.add(user) try: send_sms(phone_number, 'Din innloggingskode er: %s' % auth_code) except SMSGatewayDeliveryError: return Response({'error': 'unable to send sms'}, 503) except Exception: return Response({'error': 'server error'}, 503) return Response({'status': 'ok'})
def memberid_sms(request): """This is a membership service that lets you get your memberid by providing your phone number. Note that a lot of phone number entries in Focus are bogus (email, date of birth, or poorly formatted) and some are also foreign, which we allow for now. We are currently relying on the SMS service to fail if a bogus number happens to fall through.""" # Robots etc, just redirect them if not 'phone_mobile' in request.POST: return redirect('membership.views.service') # Start recording this request - details will be filled underway sms_request = SMSServiceRequest() sms_request.phone_number_input = request.POST['phone_mobile'] sms_request.ip = request.META['REMOTE_ADDR'] if request.user.is_authenticated(): sms_request.user = request.user sms_request.count = memberid_sms_count(request.META['REMOTE_ADDR']) if sms_request.count > 10 and request.META['REMOTE_ADDR'] not in settings.SMS_RESTRICTION_WHITELIST: sms_request.blocked = True sms_request.save() return HttpResponse(json.dumps({'status': 'too_high_frequency'})) users = lookup_users_by_phone(request.POST['phone_mobile']) if len(users) == 0: sms_request.save() return HttpResponse(json.dumps({'status': 'no_match'})) 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_household_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] else: raise Exception("A negative number of actors resulted from raw query. This is very strange, please investigate immediately.") sms_request.memberid = user.memberid sms_request.save() # Delete the actor cache in case the number was recently updated; the cache may differ from our raw lookup above user.get_actor().clear_cache() return HttpResponse(json.dumps(send_sms_receipt(request, user)))
def memberid_sms(request): """This membership service tries to send a membership receipt by SMS to the given phone number. Note that a lot of phone number entries in Focus are bogus (email, date of birth, or poorly formatted) and some are also foreign, which is allowed for now. We are currently relying on the SMS service to fail if a bogus number happens to fall through.""" if 'phone_mobile' not in request.POST: raise PermissionDenied request_count = memberid_sms_count(request.META['REMOTE_ADDR']) if request_count > 10 and request.META['REMOTE_ADDR'] not in settings.SMS_RESTRICTION_WHITELIST: return HttpResponse(json.dumps({'status': 'too_high_frequency'})) users = lookup_users_by_phone(request.POST['phone_mobile']) if len(users) == 0: return HttpResponse(json.dumps({'status': 'no_match'})) elif len(users) == 1: 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() return HttpResponse(json.dumps(send_sms_receipt(request, user))) else: # Multiple matches. This is typically a number related to members of a single family. This # is fine, since the receipt will include all family members, regardless of who it's sent # to. However, if that's not the case, we need to send one SMS for each matched but # unrelated user. recipients = [] for user in users: # If this user is not in the family of any other recipients, add them to the recipient # list if not any([r.has_family() and user in r.family.all_members() for r in recipients]): recipients.append(user) statuses = [] for user in recipients: # Delete the user cache in case the number was recently updated; the cache may differ # from our raw lookup above user.clear_cache() statuses.append(send_sms_receipt(request, user)['status']) if all([s == 'ok' for s in statuses]): return HttpResponse(json.dumps({'status': 'ok'})) else: return HttpResponse(json.dumps({'status': 'service_fail'}))
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 signup_add_participant(request, aktivitet_id, aktivitet_date_id): try: aktivitet_date = AktivitetDate.objects.select_related( *default_select_related, ).prefetch_related( *default_prefetch_related, ).get(id=aktivitet_date_id) for validation_func in [require_accepts_signups, require_stripe_account]: response = validation_func(request, aktivitet_date) if response is not None: return response except AktivitetDate.DoesNotExist: raise Http404 signup_session = SignupSession(request, aktivitet_date) context = { 'aktivitet_date': aktivitet_date, 'signup_session': signup_session, } if request.method == 'GET': return render(request, 'common/aktiviteter/show/signup/add_participant.html', context) elif request.method == 'POST': if request.POST['submit'] == 'lookup_member': context['memberid'] = request.POST['memberid'] context['lookup_memberid'] = True try: user = User.get_or_create_inactive(memberid=request.POST['memberid']) context['member'] = user # Is this user already added in the session, or a participant in # a separate group? session_participants = [p.user for p in signup_session.participants if p.user is not None] already_in_session = user in session_participants already_participant = signup_session.aktivitet_date.has_participant(user) if already_in_session or already_participant: context['already_participating'] = True return render(request, 'common/aktiviteter/show/signup/add_participant.html', context) if (aktivitet_date.only_members and not user.payment.status['is_paid']): context['member_has_not_paid'] = True return render( request, 'common/aktiviteter/show/signup/add_participant.html', context ) except: messages.error(request, 'invalid_memberid') return render(request, 'common/aktiviteter/show/signup/add_participant.html', context) elif request.POST['submit'] == 'add_member_participant': user = User.objects.get(memberid=request.POST['memberid']) # Already a participant in a separate group? This was already # checked on lookup, but ensure they wasn't signed up somewhere # else in the meantime as well. if signup_session.aktivitet_date.has_participant(user): context['memberid'] = user.memberid context['lookup_memberid'] = True context['already_participating'] = True return render(request, 'common/aktiviteter/show/signup/add_participant.html', context) # Check if they're already added in the session; if so, ignore the # duplication and just return to participants list session_participants = [p.user for p in signup_session.participants if p.user is not None] if user not in session_participants: signup_session.participants.append(SignupSessionParticipant( signup_session=signup_session, id=None, user=user, first_name=user.get_first_name(), last_name=user.get_last_name(), birth_date=user.get_birth_date(), email=user.get_email(), phone=user.get_phone_mobile(), state='signed_up', use_parent_contact_info=False, use_signee_contact_info=False, discount_code='', signee_relation='other', answers=[], extras=[], )) signup_session.save() return redirect('aktiviteter:signup_participants', aktivitet_date.aktivitet.id, aktivitet_date.id) elif request.POST['submit'] == 'add_nonuser_participant': use_signee_contact_info = request.POST.get('use_signee_contact_info') == 'on' if use_signee_contact_info: # If using the signees contact info, don't validate contact info # input context['use_signee_contact_info'] = True form = ParticipantWithoutContactInfoForm(request.POST) else: form = ParticipantForm(request.POST) if aktivitet_date.aktivitet.participant_birth_date_required: form.fields['birth_date'].required = True context['add_nonuser'] = True context['form'] = form if not form.is_valid(): return render(request, 'common/aktiviteter/show/signup/add_participant.html', context) else: first_name, last_name = form.cleaned_data['name'].rsplit(maxsplit=1) if use_signee_contact_info: email = '' phone = '' else: email = form.cleaned_data['email'] phone = form.cleaned_data['phone'] signup_session.participants.append(SignupSessionParticipant( signup_session=signup_session, id=None, user=None, first_name=first_name, last_name=last_name, birth_date=form.cleaned_data['birth_date'], email=email, phone=phone, state='signed_up', use_parent_contact_info=False, use_signee_contact_info=use_signee_contact_info, discount_code='', signee_relation='other', answers=[], extras=[], )) if not use_signee_contact_info and 'confirm_nonuser' not in request.POST: # Check if the submitted email and/or phone are already # registered in the member system, and if so, give the # signee a hint that they may add them as a member email = form.cleaned_data['email'] phone = re.sub('\s', '', form.cleaned_data['phone']) existing_email = Actor.objects.filter(email=email).exists() existing_phone = len(lookup_users_by_phone(phone)) > 0 if existing_email or existing_phone: context['existing_member'] = True context['existing_email'] = existing_email context['existing_phone'] = existing_phone return render( request, 'common/aktiviteter/show/signup/add_participant.html', context, ) signup_session.save() return redirect('aktiviteter:signup_participants', aktivitet_date.aktivitet.id, aktivitet_date.id) return render(request, 'common/aktiviteter/show/signup/add_participant.html', context)