Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Receive user name for new Terms of Service UI #1094

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
50 changes: 40 additions & 10 deletions codecov_auth/commands/owner/interactors/save_terms_agreement.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@dataclass
class TermsAgreementInput:
business_email: Optional[str] = None
name: Optional[str] = None
terms_agreement: bool = False
marketing_consent: bool = False
customer_intent: Optional[str] = None
Expand All @@ -20,7 +21,7 @@ class TermsAgreementInput:
class SaveTermsAgreementInteractor(BaseInteractor):
requires_service = False

def validate(self, input: TermsAgreementInput) -> None:
def validate_deprecated(self, input: TermsAgreementInput) -> None:
valid_customer_intents = ["Business", "BUSINESS", "Personal", "PERSONAL"]
if (
input.customer_intent
Expand All @@ -30,7 +31,11 @@ def validate(self, input: TermsAgreementInput) -> None:
if not self.current_user.is_authenticated:
raise Unauthenticated()

def update_terms_agreement(self, input: TermsAgreementInput) -> None:
def validate(self, input: TermsAgreementInput) -> None:
if not self.current_user.is_authenticated:
raise Unauthenticated()

def update_terms_agreement_deprecated(self, input: TermsAgreementInput) -> None:
self.current_user.terms_agreement = input.terms_agreement
self.current_user.terms_agreement_at = timezone.now()
self.current_user.customer_intent = input.customer_intent
Expand All @@ -44,6 +49,20 @@ def update_terms_agreement(self, input: TermsAgreementInput) -> None:
if input.marketing_consent:
self.send_data_to_marketo()

def update_terms_agreement(self, input: TermsAgreementInput) -> None:
self.current_user.terms_agreement = input.terms_agreement
self.current_user.terms_agreement_at = timezone.now()
self.current_user.name = input.name
self.current_user.email_opt_in = input.marketing_consent
self.current_user.save()

if input.business_email and input.business_email != "":
self.current_user.email = input.business_email
self.current_user.save()

if input.marketing_consent:
self.send_data_to_marketo()

def send_data_to_marketo(self) -> None:
event_data = {
"email": self.current_user.email,
Expand All @@ -52,11 +71,22 @@ def send_data_to_marketo(self) -> None:

@sync_to_async
def execute(self, input: Any) -> None:
typed_input = TermsAgreementInput(
business_email=input.get("business_email"),
terms_agreement=input.get("terms_agreement"),
marketing_consent=input.get("marketing_consent"),
customer_intent=input.get("customer_intent"),
)
self.validate(typed_input)
return self.update_terms_agreement(typed_input)
if input.get("name"):
typed_input = TermsAgreementInput(
business_email=input.get("business_email"),
terms_agreement=input.get("terms_agreement"),
marketing_consent=input.get("marketing_consent"),
name=input.get("name"),
)
self.validate(typed_input)
self.update_terms_agreement(typed_input)
# this handles the deprecated inputs
else:
typed_input = TermsAgreementInput(
business_email=input.get("business_email"),
terms_agreement=input.get("terms_agreement"),
marketing_consent=input.get("marketing_consent"),
customer_intent=input.get("customer_intent"),
)
self.validate_deprecated(typed_input)
self.update_terms_agreement_deprecated(typed_input)
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ def execute(self, current_user, input=None):
input=real_input,
)

#### Start of older tests

@freeze_time("2022-01-01T00:00:00")
def test_update_user_when_agreement_is_false(self):
def test_deprecated_update_user_when_agreement_is_false(self):
self.execute(
current_user=self.current_user,
input={"terms_agreement": False, "customer_intent": "Business"},
Expand All @@ -47,7 +49,7 @@ def test_update_user_when_agreement_is_false(self):
assert self.current_user.email == before_refresh_business_email

@freeze_time("2022-01-01T00:00:00")
def test_update_user_when_agreement_is_true(self):
def test_deprecated_update_user_when_agreement_is_true(self):
self.execute(
current_user=self.current_user,
input={"terms_agreement": True, "customer_intent": "Business"},
Expand All @@ -61,7 +63,7 @@ def test_update_user_when_agreement_is_true(self):
assert self.current_user.email == before_refresh_business_email

@freeze_time("2022-01-01T00:00:00")
def test_update_owner_and_user_when_email_is_not_empty(self):
def test_deprecated_update_owner_and_user_when_email_is_not_empty(self):
self.execute(
current_user=self.current_user,
input={
Expand All @@ -77,14 +79,14 @@ def test_update_owner_and_user_when_email_is_not_empty(self):
self.current_user.refresh_from_db()
assert self.current_user.email == "[email protected]"

def test_validation_error_when_customer_intent_invalid(self):
def test_deprecated_validation_error_when_customer_intent_invalid(self):
with pytest.raises(ValidationError):
self.execute(
current_user=self.current_user,
input={"terms_agreement": None, "customer_intent": "invalid"},
)

def test_user_is_not_authenticated(self):
def test_deprecated_user_is_not_authenticated(self):
with pytest.raises(Unauthenticated):
self.execute(
current_user=AnonymousUser(),
Expand All @@ -95,7 +97,7 @@ def test_user_is_not_authenticated(self):
},
)

def test_email_opt_in_saved_in_db(self):
def test_deprecated_email_opt_in_saved_in_db(self):
self.execute(
current_user=self.current_user,
input={
Expand All @@ -110,7 +112,9 @@ def test_email_opt_in_saved_in_db(self):
@patch(
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
)
def test_marketo_called_only_with_consent(self, mock_send_data_to_marketo):
def test_deprecated_marketo_called_only_with_consent(
self, mock_send_data_to_marketo
):
self.execute(
current_user=self.current_user,
input={
Expand All @@ -125,7 +129,9 @@ def test_marketo_called_only_with_consent(self, mock_send_data_to_marketo):
@patch(
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
)
def test_marketo_not_called_without_consent(self, mock_send_data_to_marketo):
def test_deprecated_marketo_not_called_without_consent(
self, mock_send_data_to_marketo
):
self.execute(
current_user=self.current_user,
input={
Expand All @@ -136,3 +142,115 @@ def test_marketo_not_called_without_consent(self, mock_send_data_to_marketo):
)

mock_send_data_to_marketo.assert_not_called()

#### End of older tests

@freeze_time("2022-01-01T00:00:00")
def test_update_user_when_agreement_is_false(self):
self.execute(
current_user=self.current_user,
input={
"business_email": "[email protected]",
"name": "codecov-user",
"terms_agreement": False,
},
)
before_refresh_business_email = self.current_user.email

assert self.current_user.terms_agreement == False
assert self.current_user.terms_agreement_at == self.updated_at

self.current_user.refresh_from_db()
assert self.current_user.email == before_refresh_business_email

@freeze_time("2022-01-01T00:00:00")
def test_update_user_when_agreement_is_true(self):
self.execute(
current_user=self.current_user,
input={
"business_email": "[email protected]",
"name": "codecov-user",
"terms_agreement": True,
},
)
before_refresh_business_email = self.current_user.email

assert self.current_user.terms_agreement == True
assert self.current_user.terms_agreement_at == self.updated_at

self.current_user.refresh_from_db()
assert self.current_user.email == before_refresh_business_email

@freeze_time("2022-01-01T00:00:00")
def test_update_owner_and_user_when_email_and_name_are_not_empty(self):
self.execute(
current_user=self.current_user,
input={
"business_email": "[email protected]",
"name": "codecov-user",
"terms_agreement": True,
},
)

assert self.current_user.terms_agreement == True
assert self.current_user.terms_agreement_at == self.updated_at

self.current_user.refresh_from_db()
assert self.current_user.email == "[email protected]"
assert self.current_user.name == "codecov-user"

def test_user_is_not_authenticated(self):
with pytest.raises(Unauthenticated):
self.execute(
current_user=AnonymousUser(),
input={
"business_email": "[email protected]",
"name": "codecov-user",
"terms_agreement": True,
},
)

def test_email_opt_in_saved_in_db(self):
self.execute(
current_user=self.current_user,
input={
"business_email": "[email protected]",
"name": "codecov-user",
"terms_agreement": True,
"marketing_consent": True,
},
)
self.current_user.refresh_from_db()
assert self.current_user.email_opt_in == True

@patch(
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
)
def test_marketo_called_only_with_consent(self, mock_send_data_to_marketo):
self.execute(
current_user=self.current_user,
input={
"business_email": "[email protected]",
"name": "codecov-user",
"terms_agreement": True,
"marketing_consent": True,
},
)

mock_send_data_to_marketo.assert_called_once()

@patch(
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
)
def test_marketo_not_called_without_consent(self, mock_send_data_to_marketo):
self.execute(
current_user=self.current_user,
input={
"business_email": "[email protected]",
"name": "codecov-user",
"terms_agreement": True,
"marketing_consent": False,
},
)

mock_send_data_to_marketo.assert_not_called()
49 changes: 38 additions & 11 deletions graphql_api/tests/mutation/test_save_terms_agreement.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,46 @@


class SaveTermsAgreementMutationTest(GraphQLTestHelper, TransactionTestCase):
def _request(self, owner=None):
def _request_deprecated(self, owner=None):
return self.gql_request(
query,
variables={"input": {"termsAgreement": True, "customerIntent": "Business"}},
owner=owner,
)

def _request_invalid_customer_intent(self, owner=None):
def _request_invalid_customer_intent_deprecated(self, owner=None):
return self.gql_request(
query,
variables={"input": {"termsAgreement": True, "customerIntent": "invalid"}},
owner=owner,
)

def test_unauthenticated(self):
assert self._request() == {
def _request(self, owner=None):
return self.gql_request(
query,
variables={
"input": {
"termsAgreement": True,
"businessEmail": "[email protected]",
"name": "codecov-user",
}
},
owner=owner,
)

def test_invalid_customer_intent_deprecated(self):
owner = OwnerFactory()
assert self._request_invalid_customer_intent_deprecated(owner=owner) == {
"saveTermsAgreement": {
"error": {
"__typename": "ValidationError",
"message": "Invalid customer intent provided",
}
}
}

def test_unauthenticated_deprecated(self):
assert self._request_deprecated() == {
"saveTermsAgreement": {
"error": {
"__typename": "UnauthenticatedError",
Expand All @@ -42,17 +66,20 @@ def test_unauthenticated(self):
}
}

def test_authenticated(self):
def test_authenticated_deprecated(self):
owner = OwnerFactory()
assert self._request(owner=owner) == {"saveTermsAgreement": None}
assert self._request_deprecated(owner=owner) == {"saveTermsAgreement": None}

def test_invalid_customer_intent(self):
owner = OwnerFactory()
assert self._request_invalid_customer_intent(owner=owner) == {
def test_unauthenticated(self):
assert self._request() == {
"saveTermsAgreement": {
"error": {
"__typename": "ValidationError",
"message": "Invalid customer intent provided",
"__typename": "UnauthenticatedError",
"message": "You are not authenticated",
}
}
}

def test_authenticated(self):
owner = OwnerFactory()
assert self._request(owner=owner) == {"saveTermsAgreement": None}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ input SaveTermsAgreementInput {
businessEmail: String
termsAgreement: Boolean!
marketingConsent: Boolean
name: String
customerIntent: String
}
1 change: 1 addition & 0 deletions graphql_api/types/user/user.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ type User {
student: Boolean!
studentCreatedAt: DateTime
studentUpdatedAt: DateTime
# this will no longer be updated from the UI with Appless
calvin-codecov marked this conversation as resolved.
Show resolved Hide resolved
customerIntent: String
}
Loading
Loading