Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 914b22c

Browse files
feat: Receive user name for new Terms of Service UI (#1094)
1 parent b4cc89d commit 914b22c

File tree

6 files changed

+219
-36
lines changed

6 files changed

+219
-36
lines changed

codecov_auth/commands/owner/interactors/save_terms_agreement.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
@dataclass
1313
class TermsAgreementInput:
1414
business_email: Optional[str] = None
15+
name: Optional[str] = None
1516
terms_agreement: bool = False
1617
marketing_consent: bool = False
1718
customer_intent: Optional[str] = None
@@ -20,7 +21,7 @@ class TermsAgreementInput:
2021
class SaveTermsAgreementInteractor(BaseInteractor):
2122
requires_service = False
2223

23-
def validate(self, input: TermsAgreementInput) -> None:
24+
def validate_deprecated(self, input: TermsAgreementInput) -> None:
2425
valid_customer_intents = ["Business", "BUSINESS", "Personal", "PERSONAL"]
2526
if (
2627
input.customer_intent
@@ -30,7 +31,11 @@ def validate(self, input: TermsAgreementInput) -> None:
3031
if not self.current_user.is_authenticated:
3132
raise Unauthenticated()
3233

33-
def update_terms_agreement(self, input: TermsAgreementInput) -> None:
34+
def validate(self, input: TermsAgreementInput) -> None:
35+
if not self.current_user.is_authenticated:
36+
raise Unauthenticated()
37+
38+
def update_terms_agreement_deprecated(self, input: TermsAgreementInput) -> None:
3439
self.current_user.terms_agreement = input.terms_agreement
3540
self.current_user.terms_agreement_at = timezone.now()
3641
self.current_user.customer_intent = input.customer_intent
@@ -44,6 +49,20 @@ def update_terms_agreement(self, input: TermsAgreementInput) -> None:
4449
if input.marketing_consent:
4550
self.send_data_to_marketo()
4651

52+
def update_terms_agreement(self, input: TermsAgreementInput) -> None:
53+
self.current_user.terms_agreement = input.terms_agreement
54+
self.current_user.terms_agreement_at = timezone.now()
55+
self.current_user.name = input.name
56+
self.current_user.email_opt_in = input.marketing_consent
57+
self.current_user.save()
58+
59+
if input.business_email and input.business_email != "":
60+
self.current_user.email = input.business_email
61+
self.current_user.save()
62+
63+
if input.marketing_consent:
64+
self.send_data_to_marketo()
65+
4766
def send_data_to_marketo(self) -> None:
4867
event_data = {
4968
"email": self.current_user.email,
@@ -52,11 +71,22 @@ def send_data_to_marketo(self) -> None:
5271

5372
@sync_to_async
5473
def execute(self, input: Any) -> None:
55-
typed_input = TermsAgreementInput(
56-
business_email=input.get("business_email"),
57-
terms_agreement=input.get("terms_agreement"),
58-
marketing_consent=input.get("marketing_consent"),
59-
customer_intent=input.get("customer_intent"),
60-
)
61-
self.validate(typed_input)
62-
return self.update_terms_agreement(typed_input)
74+
if input.get("name"):
75+
typed_input = TermsAgreementInput(
76+
business_email=input.get("business_email"),
77+
terms_agreement=input.get("terms_agreement"),
78+
marketing_consent=input.get("marketing_consent"),
79+
name=input.get("name"),
80+
)
81+
self.validate(typed_input)
82+
self.update_terms_agreement(typed_input)
83+
# this handles the deprecated inputs
84+
else:
85+
typed_input = TermsAgreementInput(
86+
business_email=input.get("business_email"),
87+
terms_agreement=input.get("terms_agreement"),
88+
marketing_consent=input.get("marketing_consent"),
89+
customer_intent=input.get("customer_intent"),
90+
)
91+
self.validate_deprecated(typed_input)
92+
self.update_terms_agreement_deprecated(typed_input)

codecov_auth/commands/owner/interactors/tests/test_save_terms_agreement.py

Lines changed: 126 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ def execute(self, current_user, input=None):
3232
input=real_input,
3333
)
3434

35+
#### Start of older tests
36+
3537
@freeze_time("2022-01-01T00:00:00")
36-
def test_update_user_when_agreement_is_false(self):
38+
def test_deprecated_update_user_when_agreement_is_false(self):
3739
self.execute(
3840
current_user=self.current_user,
3941
input={"terms_agreement": False, "customer_intent": "Business"},
@@ -47,7 +49,7 @@ def test_update_user_when_agreement_is_false(self):
4749
assert self.current_user.email == before_refresh_business_email
4850

4951
@freeze_time("2022-01-01T00:00:00")
50-
def test_update_user_when_agreement_is_true(self):
52+
def test_deprecated_update_user_when_agreement_is_true(self):
5153
self.execute(
5254
current_user=self.current_user,
5355
input={"terms_agreement": True, "customer_intent": "Business"},
@@ -61,7 +63,7 @@ def test_update_user_when_agreement_is_true(self):
6163
assert self.current_user.email == before_refresh_business_email
6264

6365
@freeze_time("2022-01-01T00:00:00")
64-
def test_update_owner_and_user_when_email_is_not_empty(self):
66+
def test_deprecated_update_owner_and_user_when_email_is_not_empty(self):
6567
self.execute(
6668
current_user=self.current_user,
6769
input={
@@ -77,14 +79,14 @@ def test_update_owner_and_user_when_email_is_not_empty(self):
7779
self.current_user.refresh_from_db()
7880
assert self.current_user.email == "[email protected]"
7981

80-
def test_validation_error_when_customer_intent_invalid(self):
82+
def test_deprecated_validation_error_when_customer_intent_invalid(self):
8183
with pytest.raises(ValidationError):
8284
self.execute(
8385
current_user=self.current_user,
8486
input={"terms_agreement": None, "customer_intent": "invalid"},
8587
)
8688

87-
def test_user_is_not_authenticated(self):
89+
def test_deprecated_user_is_not_authenticated(self):
8890
with pytest.raises(Unauthenticated):
8991
self.execute(
9092
current_user=AnonymousUser(),
@@ -95,7 +97,7 @@ def test_user_is_not_authenticated(self):
9597
},
9698
)
9799

98-
def test_email_opt_in_saved_in_db(self):
100+
def test_deprecated_email_opt_in_saved_in_db(self):
99101
self.execute(
100102
current_user=self.current_user,
101103
input={
@@ -110,7 +112,9 @@ def test_email_opt_in_saved_in_db(self):
110112
@patch(
111113
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
112114
)
113-
def test_marketo_called_only_with_consent(self, mock_send_data_to_marketo):
115+
def test_deprecated_marketo_called_only_with_consent(
116+
self, mock_send_data_to_marketo
117+
):
114118
self.execute(
115119
current_user=self.current_user,
116120
input={
@@ -125,7 +129,9 @@ def test_marketo_called_only_with_consent(self, mock_send_data_to_marketo):
125129
@patch(
126130
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
127131
)
128-
def test_marketo_not_called_without_consent(self, mock_send_data_to_marketo):
132+
def test_deprecated_marketo_not_called_without_consent(
133+
self, mock_send_data_to_marketo
134+
):
129135
self.execute(
130136
current_user=self.current_user,
131137
input={
@@ -136,3 +142,115 @@ def test_marketo_not_called_without_consent(self, mock_send_data_to_marketo):
136142
)
137143

138144
mock_send_data_to_marketo.assert_not_called()
145+
146+
#### End of older tests
147+
148+
@freeze_time("2022-01-01T00:00:00")
149+
def test_update_user_when_agreement_is_false(self):
150+
self.execute(
151+
current_user=self.current_user,
152+
input={
153+
"business_email": "[email protected]",
154+
"name": "codecov-user",
155+
"terms_agreement": False,
156+
},
157+
)
158+
before_refresh_business_email = self.current_user.email
159+
160+
assert self.current_user.terms_agreement == False
161+
assert self.current_user.terms_agreement_at == self.updated_at
162+
163+
self.current_user.refresh_from_db()
164+
assert self.current_user.email == before_refresh_business_email
165+
166+
@freeze_time("2022-01-01T00:00:00")
167+
def test_update_user_when_agreement_is_true(self):
168+
self.execute(
169+
current_user=self.current_user,
170+
input={
171+
"business_email": "[email protected]",
172+
"name": "codecov-user",
173+
"terms_agreement": True,
174+
},
175+
)
176+
before_refresh_business_email = self.current_user.email
177+
178+
assert self.current_user.terms_agreement == True
179+
assert self.current_user.terms_agreement_at == self.updated_at
180+
181+
self.current_user.refresh_from_db()
182+
assert self.current_user.email == before_refresh_business_email
183+
184+
@freeze_time("2022-01-01T00:00:00")
185+
def test_update_owner_and_user_when_email_and_name_are_not_empty(self):
186+
self.execute(
187+
current_user=self.current_user,
188+
input={
189+
"business_email": "[email protected]",
190+
"name": "codecov-user",
191+
"terms_agreement": True,
192+
},
193+
)
194+
195+
assert self.current_user.terms_agreement == True
196+
assert self.current_user.terms_agreement_at == self.updated_at
197+
198+
self.current_user.refresh_from_db()
199+
assert self.current_user.email == "[email protected]"
200+
assert self.current_user.name == "codecov-user"
201+
202+
def test_user_is_not_authenticated(self):
203+
with pytest.raises(Unauthenticated):
204+
self.execute(
205+
current_user=AnonymousUser(),
206+
input={
207+
"business_email": "[email protected]",
208+
"name": "codecov-user",
209+
"terms_agreement": True,
210+
},
211+
)
212+
213+
def test_email_opt_in_saved_in_db(self):
214+
self.execute(
215+
current_user=self.current_user,
216+
input={
217+
"business_email": "[email protected]",
218+
"name": "codecov-user",
219+
"terms_agreement": True,
220+
"marketing_consent": True,
221+
},
222+
)
223+
self.current_user.refresh_from_db()
224+
assert self.current_user.email_opt_in == True
225+
226+
@patch(
227+
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
228+
)
229+
def test_marketo_called_only_with_consent(self, mock_send_data_to_marketo):
230+
self.execute(
231+
current_user=self.current_user,
232+
input={
233+
"business_email": "[email protected]",
234+
"name": "codecov-user",
235+
"terms_agreement": True,
236+
"marketing_consent": True,
237+
},
238+
)
239+
240+
mock_send_data_to_marketo.assert_called_once()
241+
242+
@patch(
243+
"codecov_auth.commands.owner.interactors.save_terms_agreement.SaveTermsAgreementInteractor.send_data_to_marketo"
244+
)
245+
def test_marketo_not_called_without_consent(self, mock_send_data_to_marketo):
246+
self.execute(
247+
current_user=self.current_user,
248+
input={
249+
"business_email": "[email protected]",
250+
"name": "codecov-user",
251+
"terms_agreement": True,
252+
"marketing_consent": False,
253+
},
254+
)
255+
256+
mock_send_data_to_marketo.assert_not_called()

graphql_api/tests/mutation/test_save_terms_agreement.py

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,46 @@
1818

1919

2020
class SaveTermsAgreementMutationTest(GraphQLTestHelper, TransactionTestCase):
21-
def _request(self, owner=None):
21+
def _request_deprecated(self, owner=None):
2222
return self.gql_request(
2323
query,
2424
variables={"input": {"termsAgreement": True, "customerIntent": "Business"}},
2525
owner=owner,
2626
)
2727

28-
def _request_invalid_customer_intent(self, owner=None):
28+
def _request_invalid_customer_intent_deprecated(self, owner=None):
2929
return self.gql_request(
3030
query,
3131
variables={"input": {"termsAgreement": True, "customerIntent": "invalid"}},
3232
owner=owner,
3333
)
3434

35-
def test_unauthenticated(self):
36-
assert self._request() == {
35+
def _request(self, owner=None):
36+
return self.gql_request(
37+
query,
38+
variables={
39+
"input": {
40+
"termsAgreement": True,
41+
"businessEmail": "[email protected]",
42+
"name": "codecov-user",
43+
}
44+
},
45+
owner=owner,
46+
)
47+
48+
def test_invalid_customer_intent_deprecated(self):
49+
owner = OwnerFactory()
50+
assert self._request_invalid_customer_intent_deprecated(owner=owner) == {
51+
"saveTermsAgreement": {
52+
"error": {
53+
"__typename": "ValidationError",
54+
"message": "Invalid customer intent provided",
55+
}
56+
}
57+
}
58+
59+
def test_unauthenticated_deprecated(self):
60+
assert self._request_deprecated() == {
3761
"saveTermsAgreement": {
3862
"error": {
3963
"__typename": "UnauthenticatedError",
@@ -42,17 +66,20 @@ def test_unauthenticated(self):
4266
}
4367
}
4468

45-
def test_authenticated(self):
69+
def test_authenticated_deprecated(self):
4670
owner = OwnerFactory()
47-
assert self._request(owner=owner) == {"saveTermsAgreement": None}
71+
assert self._request_deprecated(owner=owner) == {"saveTermsAgreement": None}
4872

49-
def test_invalid_customer_intent(self):
50-
owner = OwnerFactory()
51-
assert self._request_invalid_customer_intent(owner=owner) == {
73+
def test_unauthenticated(self):
74+
assert self._request() == {
5275
"saveTermsAgreement": {
5376
"error": {
54-
"__typename": "ValidationError",
55-
"message": "Invalid customer intent provided",
77+
"__typename": "UnauthenticatedError",
78+
"message": "You are not authenticated",
5679
}
5780
}
5881
}
82+
83+
def test_authenticated(self):
84+
owner = OwnerFactory()
85+
assert self._request(owner=owner) == {"saveTermsAgreement": None}

graphql_api/types/mutation/save_terms_agreement/save_terms_agreement.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ input SaveTermsAgreementInput {
88
businessEmail: String
99
termsAgreement: Boolean!
1010
marketingConsent: Boolean
11+
name: String
1112
customerIntent: String
1213
}

graphql_api/types/user/user.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ type User {
55
student: Boolean!
66
studentCreatedAt: DateTime
77
studentUpdatedAt: DateTime
8+
# this will no longer be updated from the UI with Appless
89
customerIntent: String
910
}

0 commit comments

Comments
 (0)