add index to RelayNumber and more review changes
This commit is contained in:
Родитель
7776f5b105
Коммит
0a67f6264f
|
@ -6,6 +6,7 @@ omit =
|
|||
*tests/*,
|
||||
*wsgi.py,
|
||||
manage.py,
|
||||
env/*,
|
||||
node_modules/*,
|
||||
|
||||
[run]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import vobject
|
||||
|
||||
from django.conf import settings
|
||||
from django.templatetags.static import static
|
||||
|
||||
from rest_framework import renderers
|
||||
|
||||
|
@ -14,7 +13,7 @@ class vCardRenderer(renderers.BaseRenderer):
|
|||
vCard = vobject.vCard()
|
||||
vCard.add("FN").value = "Firefox Relay"
|
||||
# TODO: fix static urls
|
||||
photo_url = settings.SITE_ORIGIN + static("placeholder-logo.svg")
|
||||
photo_url = settings.SITE_ORIGIN + "/static/images/relay-logo.svg"
|
||||
vCard.add("PHOTO").value = photo_url
|
||||
vCard.add("LOGO").value = photo_url
|
||||
vCard.add("EMAIL").value = "support@relay.firefox.com"
|
||||
|
|
|
@ -13,7 +13,7 @@ from phones.tests.models_tests import make_phone_test_user
|
|||
|
||||
|
||||
@pytest.fixture()
|
||||
def phone_user():
|
||||
def phone_user(db):
|
||||
yield make_phone_test_user()
|
||||
|
||||
|
||||
|
@ -75,7 +75,6 @@ def test_phone_endspoints_require_auth_and_phone_service(endpoint):
|
|||
assert response.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_get_responds_200(phone_user):
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
|
@ -84,7 +83,6 @@ def test_realphone_get_responds_200(phone_user):
|
|||
assert response.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_post_invalid_e164_number_no_request_country(phone_user):
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
|
@ -97,7 +95,6 @@ def test_realphone_post_invalid_e164_number_no_request_country(phone_user):
|
|||
assert "Number Must Be In E.164 Format" in response.data[0].title()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_post_valid_e164_number_in_unsupported_country(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
|
@ -121,7 +118,6 @@ def test_realphone_post_valid_e164_number_in_unsupported_country(
|
|||
assert "Available In The Us" in response.data[0].title()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_post_valid_es164_number(phone_user, mocked_twilio_client):
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
|
@ -151,7 +147,45 @@ def test_realphone_post_valid_es164_number(phone_user, mocked_twilio_client):
|
|||
assert "verification code" in call_kwargs['body']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_post_valid_es164_number_already_sent_code(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
number = "+12223334444"
|
||||
path = "/api/v1/realphone/"
|
||||
data = {"number": number}
|
||||
|
||||
mock_fetch = Mock(return_value=Mock(
|
||||
country_code="US", phone_number=number, carrier="verizon"
|
||||
))
|
||||
mocked_twilio_client.lookups.v1.phone_numbers = Mock(
|
||||
return_value=Mock(fetch=mock_fetch)
|
||||
)
|
||||
|
||||
# the first POST should work fine
|
||||
response = client.post(path, data, format='json')
|
||||
assert response.status_code == 201
|
||||
assert response.data['number'] == number
|
||||
assert response.data['verified'] == False
|
||||
assert response.data['verification_sent_date'] != ''
|
||||
assert "Sent verification" in response.data['message']
|
||||
|
||||
mocked_twilio_client.lookups.v1.phone_numbers.assert_called_once_with(number)
|
||||
mock_fetch.assert_called_once()
|
||||
mocked_twilio_client.messages.create.assert_called_once()
|
||||
call_kwargs = mocked_twilio_client.messages.create.call_args.kwargs
|
||||
assert call_kwargs['to'] == number
|
||||
assert "verification code" in call_kwargs['body']
|
||||
|
||||
mocked_twilio_client.reset_mock()
|
||||
# the second POST should not send a new verification code
|
||||
response = client.post(path, data, format='json')
|
||||
assert response.status_code == 409
|
||||
mocked_twilio_client.lookups.v1.phone_numbers.assert_not_called()
|
||||
mock_fetch.assert_not_called()
|
||||
mocked_twilio_client.messages.create.assert_not_called()
|
||||
|
||||
def test_realphone_post_valid_verification_code(
|
||||
phone_user,
|
||||
mocked_twilio_client
|
||||
|
@ -181,7 +215,6 @@ def test_realphone_post_valid_verification_code(
|
|||
mock_fetch.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_post_invalid_verification_code(
|
||||
phone_user,
|
||||
mocked_twilio_client
|
||||
|
@ -212,13 +245,14 @@ def test_realphone_post_invalid_verification_code(
|
|||
mock_fetch.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_patch_verification_code(
|
||||
phone_user,
|
||||
mocked_twilio_client
|
||||
):
|
||||
number = "+12223334444"
|
||||
real_phone = RealPhone.objects.create(user=phone_user, number=number)
|
||||
real_phone = RealPhone.objects.create(
|
||||
user=phone_user, number=number, verified=False
|
||||
)
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
path = f"/api/v1/realphone/{real_phone.id}/"
|
||||
|
@ -242,7 +276,71 @@ def test_realphone_patch_verification_code(
|
|||
mock_fetch.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_realphone_patch_verification_code_twice(
|
||||
phone_user,
|
||||
mocked_twilio_client
|
||||
):
|
||||
number = "+12223334444"
|
||||
real_phone = RealPhone.objects.create(
|
||||
user=phone_user, number=number, verified=False
|
||||
)
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
path = f"/api/v1/realphone/{real_phone.id}/"
|
||||
data = {
|
||||
"number": number, "verification_code": real_phone.verification_code
|
||||
}
|
||||
|
||||
mock_fetch = Mock(return_value=Mock(
|
||||
country_code="US", phone_number=number, carrier="verizon"
|
||||
))
|
||||
mocked_twilio_client.lookups.v1.phone_numbers = Mock(
|
||||
return_value=Mock(fetch=mock_fetch)
|
||||
)
|
||||
|
||||
response = client.patch(path, data, format='json')
|
||||
assert response.status_code == 200
|
||||
assert response.data['number'] == number
|
||||
assert response.data['verified'] == True
|
||||
assert response.data['verified_date'] != ''
|
||||
|
||||
mock_fetch.assert_not_called()
|
||||
|
||||
response = client.patch(path, data, format='json')
|
||||
assert response.status_code == 200
|
||||
assert response.data['number'] == number
|
||||
assert response.data['verified'] == True
|
||||
assert response.data['verified_date'] != ''
|
||||
|
||||
|
||||
def test_realphone_patch_invalid_number(
|
||||
phone_user,
|
||||
mocked_twilio_client
|
||||
):
|
||||
number = "+12223334444"
|
||||
real_phone = RealPhone.objects.create(user=phone_user, number=number)
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
path = f"/api/v1/realphone/{real_phone.id}/"
|
||||
data = {
|
||||
"number": "+98887776666", "verification_code": "invalid"
|
||||
}
|
||||
|
||||
mock_fetch = Mock(return_value=Mock(
|
||||
country_code="US", phone_number=number, carrier="verizon"
|
||||
))
|
||||
mocked_twilio_client.lookups.v1.phone_numbers = Mock(
|
||||
return_value=Mock(fetch=mock_fetch)
|
||||
)
|
||||
|
||||
response = client.patch(path, data, format='json')
|
||||
assert response.status_code == 400
|
||||
real_phone.refresh_from_db()
|
||||
assert real_phone.verified == False
|
||||
assert real_phone.verified_date == None
|
||||
|
||||
mock_fetch.assert_not_called()
|
||||
|
||||
def test_realphone_patch_invalid_verification_code(
|
||||
phone_user,
|
||||
mocked_twilio_client
|
||||
|
@ -272,7 +370,6 @@ def test_realphone_patch_invalid_verification_code(
|
|||
mock_fetch.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relaynumber_suggestions_bad_request_for_user_without_real_phone(
|
||||
phone_user
|
||||
):
|
||||
|
@ -289,7 +386,6 @@ def test_relaynumber_suggestions_bad_request_for_user_without_real_phone(
|
|||
assert response.status_code == 400
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relaynumber_suggestions_bad_request_for_user_already_with_number(
|
||||
phone_user
|
||||
):
|
||||
|
@ -302,7 +398,6 @@ def test_relaynumber_suggestions_bad_request_for_user_already_with_number(
|
|||
assert response.status_code == 400
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relaynumber_suggestions(phone_user):
|
||||
real_phone = "+12223334444"
|
||||
RealPhone.objects.create(
|
||||
|
@ -322,7 +417,6 @@ def test_relaynumber_suggestions(phone_user):
|
|||
assert "same_area_options" in data_keys
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relaynumber_search_requires_param(phone_user):
|
||||
client = APIClient()
|
||||
client.force_authenticate(phone_user)
|
||||
|
@ -333,7 +427,6 @@ def test_relaynumber_search_requires_param(phone_user):
|
|||
assert response.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relaynumber_search_by_location(phone_user, mocked_twilio_client):
|
||||
mock_list = Mock(return_value=[])
|
||||
mocked_twilio_client.available_phone_numbers=Mock(return_value = (
|
||||
|
@ -356,7 +449,6 @@ def test_relaynumber_search_by_location(phone_user, mocked_twilio_client):
|
|||
]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_relaynumber_search_by_area_code(phone_user, mocked_twilio_client):
|
||||
mock_list = Mock(return_value=[])
|
||||
mocked_twilio_client.available_phone_numbers=Mock(return_value = (
|
||||
|
@ -398,7 +490,6 @@ def test_vcard_wrong_lookup_key():
|
|||
assert response.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_vcard_valid_lookup_key(phone_user):
|
||||
real_phone = "+12223334444"
|
||||
RealPhone.objects.create(user=phone_user, verified=True, number=real_phone)
|
||||
|
@ -413,7 +504,7 @@ def test_vcard_valid_lookup_key(phone_user):
|
|||
|
||||
assert response.status_code == 200
|
||||
assert response.data['number'] == relay_number
|
||||
assert response.headers['Content-Disposition'] == 'attachment; filename=+19998887777'
|
||||
assert response.headers['Content-Disposition'] == 'attachment; filename=+19998887777.vcf'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
@ -450,7 +541,6 @@ def test_inbound_sms_valid_twilio_signature_bad_data(mocked_twilio_validator):
|
|||
assert "Missing From, To, Or Body." in response.data[0].title()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_inbound_sms_valid_twilio_signature_good_data(
|
||||
phone_user, mocked_twilio_client, mocked_twilio_validator
|
||||
):
|
||||
|
|
37
api/views.py
37
api/views.py
|
@ -1,4 +1,4 @@
|
|||
from django.http.response import Http404
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
import phonenumbers
|
||||
|
||||
from django.apps import apps
|
||||
|
@ -23,7 +23,7 @@ from emails.models import (
|
|||
RelayAddress,
|
||||
)
|
||||
from phones.models import (
|
||||
RealPhone, RelayNumber,
|
||||
RealPhone, RelayNumber, get_pending_unverified_realphone_records,
|
||||
get_valid_realphone_verification_record,
|
||||
suggested_numbers, location_numbers, area_code_numbers, twilio_client
|
||||
)
|
||||
|
@ -224,7 +224,7 @@ class RealPhoneViewSet(SaveToRequestUser, viewsets.ModelViewSet):
|
|||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# First, check if the request includes a valid verification_code
|
||||
# Check if the request includes a valid verification_code
|
||||
# value, look for any un-expired record that matches both the phone
|
||||
# number and verification code and mark it verified.
|
||||
verification_code = serializer.validated_data.get(
|
||||
|
@ -249,6 +249,16 @@ class RealPhoneViewSet(SaveToRequestUser, viewsets.ModelViewSet):
|
|||
response_data, status=201, headers=headers
|
||||
)
|
||||
|
||||
# to prevent abusive sending of verification messages,
|
||||
# check if there is an un-expired verification code for the user
|
||||
pending_unverified_records = get_pending_unverified_realphone_records(
|
||||
serializer.validated_data["number"]
|
||||
)
|
||||
if pending_unverified_records:
|
||||
raise ConflictError(
|
||||
"An unverified record already exists for this number.",
|
||||
)
|
||||
|
||||
# We call an additional _validate_number function with the request
|
||||
# to try to parse the number as a local national number in the
|
||||
# request.country attribute
|
||||
|
@ -290,6 +300,8 @@ class RealPhoneViewSet(SaveToRequestUser, viewsets.ModelViewSet):
|
|||
[e164]: https://en.wikipedia.org/wiki/E.164
|
||||
"""
|
||||
instance = self.get_object()
|
||||
if request.data["number"] != instance.number:
|
||||
raise exceptions.ValidationError("Invalid number for ID.")
|
||||
# TODO: check verification_sent_date is not "expired"?
|
||||
# Note: the RealPhone.save() logic should prevent expired verifications
|
||||
if ("verification_code" not in request.data or
|
||||
|
@ -372,7 +384,9 @@ class RelayNumberViewSet(SaveToRequestUser, viewsets.ModelViewSet):
|
|||
|
||||
|
||||
def _validate_number(request):
|
||||
parsed_number = _parse_number(request.data["number"], request)
|
||||
parsed_number = _parse_number(
|
||||
request.data["number"], getattr(request, "country", None)
|
||||
)
|
||||
if not parsed_number:
|
||||
country = None
|
||||
if hasattr(request, "country"):
|
||||
|
@ -395,17 +409,17 @@ def _validate_number(request):
|
|||
return number_details
|
||||
|
||||
|
||||
def _parse_number(number, request):
|
||||
def _parse_number(number, country=None):
|
||||
try:
|
||||
# First try to parse assuming number is E.164 with country prefix
|
||||
return phonenumbers.parse(number)
|
||||
except phonenumbers.phonenumberutil.NumberParseException as e:
|
||||
if (e.error_type == e.INVALID_COUNTRY_CODE and
|
||||
hasattr(request, "country")):
|
||||
country is not None):
|
||||
try:
|
||||
# Try to parse, assuming number is local national format
|
||||
# in the detected request country
|
||||
return phonenumbers.parse(number, request.country)
|
||||
return phonenumbers.parse(number, country)
|
||||
except Exception:
|
||||
return None
|
||||
return None
|
||||
|
@ -441,7 +455,7 @@ def vCard(request, lookup_key):
|
|||
number = relay_number.number
|
||||
|
||||
resp = response.Response({"number": number})
|
||||
resp["Content-Disposition"] = f"attachment; filename={number}"
|
||||
resp["Content-Disposition"] = f"attachment; filename={number}.vcf"
|
||||
return resp
|
||||
|
||||
|
||||
|
@ -488,8 +502,11 @@ def inbound_sms(request):
|
|||
"Message missing From, To, Or Body."
|
||||
)
|
||||
|
||||
relay_number = RelayNumber.objects.get(number=inbound_to)
|
||||
real_phone = RealPhone.objects.get(user=relay_number.user, verified=True)
|
||||
try:
|
||||
relay_number = RelayNumber.objects.get(number=inbound_to)
|
||||
real_phone = RealPhone.objects.get(user=relay_number.user, verified=True)
|
||||
except ObjectDoesNotExist:
|
||||
raise exceptions.ValidationError("Could not find relay number.")
|
||||
client = twilio_client()
|
||||
client.messages.create(
|
||||
from_=relay_number.number,
|
||||
|
|
|
@ -76,7 +76,7 @@ correctly. The first message in the Relay phone flow is the verification code:
|
|||
4. Use the `POST /api/v1/realphone/` API endpoint again to verify your real
|
||||
number. This time, submit your real number AND the verification code
|
||||
together:
|
||||
* `{"number": "+12223334444", "verification_code": 123456}`
|
||||
* `{"number": "+12223334444", "verification_code": "123456"}`
|
||||
|
||||
[buy-fonez]: https://accounts.stage.mozaws.net/subscriptions/products/prod_LgQiSgNi4xL7dq
|
||||
[stripe-test-cards]: https://stripe.com/docs/testing#cards
|
||||
|
@ -100,6 +100,7 @@ make this easier.
|
|||
```
|
||||
Note: You will need ngrok premium to get a static subdomain.
|
||||
3. Add `your-subdomain.ngrok.io` to your `.env` `DJANGO_ALLOWED_HOST`
|
||||
4. Set your `.env` `SITE_ORIGIN` to `your-subdomain.ngrok.io`
|
||||
4. Run `ngrok start relay`
|
||||
5. Hit https://your-subdomain.ngrok.io/api/v1/docs/ to check that it's working.
|
||||
|
||||
|
@ -120,7 +121,7 @@ local app URL to its call and text webhooks, and set its app ID to your
|
|||
* Friendly name: "your-host Relay"
|
||||
* Voice request URL: https://your-host.ngrok.io/api/v1/inbound_call HTTP
|
||||
POST
|
||||
* Messaging requst URL: https://your-host.ngrok.io/api/v1/inbound_sms HTTP
|
||||
* Messaging request URL: https://your-host.ngrok.io/api/v1/inbound_sms HTTP
|
||||
POST
|
||||
3. Click "Save"
|
||||
4. Click the newly-created app
|
||||
|
|
|
@ -20,15 +20,21 @@ class PhonesConfig(AppConfig):
|
|||
settings.TWILIO_ACCOUNT_SID,
|
||||
settings.TWILIO_AUTH_TOKEN
|
||||
)
|
||||
self._twilio_test_client = Client(
|
||||
settings.TWILIO_TEST_ACCOUNT_SID,
|
||||
settings.TWILIO_TEST_AUTH_TOKEN
|
||||
)
|
||||
self._twilio_validator = RequestValidator(
|
||||
settings.TWILIO_AUTH_TOKEN
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("exception during Twilio connect")
|
||||
logger.exception(
|
||||
"exception creating Twilio client and/or validator"
|
||||
)
|
||||
if settings.TWILIO_TEST_ACCOUNT_SID:
|
||||
try:
|
||||
self._twilio_test_client = Client(
|
||||
settings.TWILIO_TEST_ACCOUNT_SID,
|
||||
settings.TWILIO_TEST_AUTH_TOKEN
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("exception creating Twilio test client")
|
||||
|
||||
@property
|
||||
def twilio_client(self):
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.13 on 2022-07-11 20:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('phones', '0015_alter_realphone_verification_sent_date'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='relaynumber',
|
||||
name='number',
|
||||
field=models.CharField(db_index=True, max_length=15),
|
||||
),
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
from datetime import datetime, timedelta, timezone
|
||||
import math
|
||||
import random
|
||||
import secrets
|
||||
import string
|
||||
|
||||
from django.apps import apps
|
||||
|
@ -41,11 +42,20 @@ def get_expired_unverified_realphone_records(number):
|
|||
)
|
||||
)
|
||||
|
||||
def get_pending_unverified_realphone_records(number):
|
||||
return RealPhone.objects.filter(
|
||||
number=number,
|
||||
verified=False,
|
||||
verification_sent_date__gt=(
|
||||
datetime.now(timezone.utc) -
|
||||
timedelta(0, 60*MAX_MINUTES_TO_VERIFY_REAL_PHONE)
|
||||
)
|
||||
)
|
||||
|
||||
def get_existing_realphone_record(user, number):
|
||||
def get_verified_realphone_records(user):
|
||||
return RealPhone.objects.filter(
|
||||
user=user, verified=True
|
||||
).exclude(number=number)
|
||||
)
|
||||
|
||||
|
||||
def get_valid_realphone_verification_record(user, number, verification_code):
|
||||
|
@ -83,15 +93,6 @@ class RealPhone(models.Model):
|
|||
]
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# We are not ready to support multiple real phone numbers per user,
|
||||
# so raise an exception if this save() would create a second
|
||||
# RealPhone record for the user
|
||||
other_number_record = (
|
||||
get_existing_realphone_record(self.user, self.number)
|
||||
)
|
||||
if other_number_record:
|
||||
raise BadRequest("RealPhone.save(): Another real number already exists for this user.")
|
||||
|
||||
# delete any expired unverified RealPhone records for this number
|
||||
# note: it doesn't matter which user is trying to create a new
|
||||
# RealPhone record - any expired unverified record for the number
|
||||
|
@ -101,6 +102,22 @@ class RealPhone(models.Model):
|
|||
)
|
||||
expired_verification_records.delete()
|
||||
|
||||
# We are not ready to support multiple real phone numbers per user,
|
||||
# so raise an exception if this save() would create a second
|
||||
# RealPhone record for the user
|
||||
user_verified_number_records = (
|
||||
get_verified_realphone_records(self.user)
|
||||
)
|
||||
for verified_number in user_verified_number_records:
|
||||
if (verified_number.number == self.number and
|
||||
verified_number.verification_code == self.verification_code
|
||||
):
|
||||
# User is verifying the same number twice
|
||||
return super().save(*args, **kwargs)
|
||||
else:
|
||||
raise BadRequest("User already has a verified number.")
|
||||
|
||||
|
||||
# call super save to save into the DB
|
||||
# See also: realphone_post_save receiver below
|
||||
return super().save(*args, **kwargs)
|
||||
|
@ -130,14 +147,14 @@ def realphone_post_save(sender, instance, created, **kwargs):
|
|||
|
||||
def vcard_lookup_key_default():
|
||||
return ''.join(
|
||||
random.choice(string.ascii_letters + string.digits)
|
||||
secrets.choice(string.ascii_letters + string.digits)
|
||||
for i in range(6)
|
||||
)
|
||||
|
||||
|
||||
class RelayNumber(models.Model):
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
number = models.CharField(max_length=15)
|
||||
number = models.CharField(max_length=15, db_index=True)
|
||||
location = models.CharField(max_length=255)
|
||||
vcard_lookup_key = models.CharField(
|
||||
max_length=6,
|
||||
|
|
|
@ -62,11 +62,10 @@ def upgrade_test_user_to_phone(user):
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def phone_user():
|
||||
def phone_user(db):
|
||||
yield make_phone_test_user()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_valid_realphone_verification_record_returns_object(phone_user):
|
||||
number = "+12223334444"
|
||||
real_phone = RealPhone.objects.create(
|
||||
|
@ -81,7 +80,6 @@ def test_get_valid_realphone_verification_record_returns_object(phone_user):
|
|||
assert record.number == number
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_valid_realphone_verification_record_returns_none(phone_user):
|
||||
number = "+12223334444"
|
||||
real_phone = RealPhone.objects.create(
|
||||
|
@ -98,7 +96,6 @@ def test_get_valid_realphone_verification_record_returns_none(phone_user):
|
|||
assert record == None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_realphone_creates_twilio_message(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
|
@ -113,7 +110,6 @@ def test_create_realphone_creates_twilio_message(
|
|||
assert "verification code" in call_kwargs['body']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_second_realphone_for_user_raises_exception(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
|
@ -133,7 +129,6 @@ def test_create_second_realphone_for_user_raises_exception(
|
|||
pytest.fail("Should have raised BadRequest exception")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_realphone_deletes_expired_unverified_records(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
|
@ -167,7 +162,6 @@ def test_create_realphone_deletes_expired_unverified_records(
|
|||
mock_twilio_client.messages.create.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_mark_realphone_verified_sets_verified_and_date(phone_user):
|
||||
real_phone = RealPhone.objects.create(
|
||||
user=phone_user,
|
||||
|
@ -178,7 +172,6 @@ def test_mark_realphone_verified_sets_verified_and_date(phone_user):
|
|||
assert real_phone.verified_date
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_relaynumber_creates_twilio_incoming_number_and_sends_welcome(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
|
@ -208,7 +201,6 @@ def test_create_relaynumber_creates_twilio_incoming_number_and_sends_welcome(
|
|||
assert relay_number_obj.vcard_lookup_key in call_kwargs["media_url"][0]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_suggested_numbers_bad_request_for_user_without_real_phone(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
|
@ -221,7 +213,6 @@ def test_suggested_numbers_bad_request_for_user_without_real_phone(
|
|||
pytest.fail("Should have raised BadRequest exception")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_suggested_numbers_bad_request_for_user_who_already_has_number(
|
||||
phone_user, mocked_twilio_client
|
||||
):
|
||||
|
@ -238,7 +229,6 @@ def test_suggested_numbers_bad_request_for_user_who_already_has_number(
|
|||
pytest.fail("Should have raised BadRequest exception")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_suggested_numbers(phone_user, mocked_twilio_client):
|
||||
real_phone = "+12223334444"
|
||||
RealPhone.objects.create(user=phone_user, verified=True, number=real_phone)
|
||||
|
@ -262,7 +252,6 @@ def test_suggested_numbers(phone_user, mocked_twilio_client):
|
|||
]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_location_numbers(mocked_twilio_client):
|
||||
mock_twilio_client = mocked_twilio_client
|
||||
mock_list = Mock(return_value=[Mock() for i in range(5)])
|
||||
|
@ -281,7 +270,6 @@ def test_location_numbers(mocked_twilio_client):
|
|||
]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_area_code_numbers(mocked_twilio_client):
|
||||
mock_twilio_client = mocked_twilio_client
|
||||
mock_list = Mock(return_value=[Mock() for i in range(5)])
|
||||
|
|
Загрузка…
Ссылка в новой задаче