-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add failed statuses for groups (#2159)
- Loading branch information
1 parent
ab25983
commit 550f3cf
Showing
11 changed files
with
251 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,4 @@ | |
Your project description goes here. | ||
""" | ||
|
||
__version__ = "4.20.12" | ||
__version__ = "4.20.13" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
enterprise/migrations/0216_enterprisegroupmembership_errored_at_and_more.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Generated by Django 4.2.13 on 2024-06-24 18:28 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('enterprise', '0215_remove_enterprisecustomer_career_engagement_network_message_and_more'), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name='enterprisegroupmembership', | ||
name='errored_at', | ||
field=models.DateTimeField(blank=True, default=None, help_text='The last time the membership action was in an error state. Null means the membership is not errored.', null=True), | ||
), | ||
migrations.AddField( | ||
model_name='historicalenterprisegroupmembership', | ||
name='errored_at', | ||
field=models.DateTimeField(blank=True, default=None, help_text='The last time the membership action was in an error state. Null means the membership is not errored.', null=True), | ||
), | ||
migrations.AlterField( | ||
model_name='enterprisegroupmembership', | ||
name='status', | ||
field=models.CharField(blank=True, choices=[('removed', 'Removed'), ('accepted', 'Accepted'), ('pending', 'Pending'), ('internal_api_error', 'Internal API error'), ('email_error', 'Email error')], default='pending', help_text='Current status of the membership record', max_length=20, null=True, verbose_name='Membership Status'), | ||
), | ||
migrations.AlterField( | ||
model_name='historicalenterprisegroupmembership', | ||
name='status', | ||
field=models.CharField(blank=True, choices=[('removed', 'Removed'), ('accepted', 'Accepted'), ('pending', 'Pending'), ('internal_api_error', 'Internal API error'), ('email_error', 'Email error')], default='pending', help_text='Current status of the membership record', max_length=20, null=True, verbose_name='Membership Status'), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8552,6 +8552,30 @@ def test_patch_with_bad_request_customer_to_change_to(self): | |
response = self.client.patch(url, data=request_data) | ||
assert response.status_code == 401 | ||
|
||
def test_update_pending_learner_status(self): | ||
""" | ||
Test that the PATCH endpoint updates pending learner status and errored at time | ||
""" | ||
# url: 'http://testserver/enterprise/api/v1/enterprise_group/<group uuid>/learners/' | ||
url = settings.TEST_SERVER + reverse( | ||
'enterprise-group-learners', | ||
kwargs={'group_uuid': self.group_1.uuid}, | ||
) | ||
new_uuid = uuid.uuid4() | ||
new_customer = EnterpriseCustomerFactory(uuid=new_uuid) | ||
self.set_multiple_enterprise_roles_to_jwt([ | ||
(ENTERPRISE_ADMIN_ROLE, self.enterprise_customer.pk), | ||
(ENTERPRISE_ADMIN_ROLE, self.group_2.enterprise_customer.pk), | ||
(ENTERPRISE_ADMIN_ROLE, new_customer.pk), | ||
]) | ||
request_data = { | ||
'learner': '[email protected]', | ||
'status': 'email_error', | ||
'errored_at': localized_utcnow()} | ||
response = self.client.patch(url, data=request_data) | ||
assert response.status_code == 201 | ||
assert response.json() == 'Successfully updated learner record for learner email [email protected]' | ||
|
||
@mock.patch('enterprise.tasks.send_group_membership_removal_notification.delay', return_value=mock.MagicMock()) | ||
def test_successful_remove_all_learners_from_group(self, mock_send_group_membership_removal_notification): | ||
""" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,8 @@ | |
from datetime import datetime | ||
from unittest import mock | ||
|
||
from pytest import mark | ||
from braze.exceptions import BrazeClientError | ||
from pytest import mark, raises | ||
|
||
from enterprise.api_client.braze import ENTERPRISE_BRAZE_ALIAS_LABEL | ||
from enterprise.constants import SSO_BRAZE_CAMPAIGN_ID | ||
|
@@ -21,7 +22,7 @@ | |
send_group_membership_removal_notification, | ||
send_sso_configured_email, | ||
) | ||
from enterprise.utils import serialize_notification_content | ||
from enterprise.utils import localized_utcnow, serialize_notification_content | ||
from test_utils.factories import ( | ||
EnterpriseCustomerFactory, | ||
EnterpriseCustomerUserFactory, | ||
|
@@ -267,6 +268,58 @@ def test_send_group_membership_invitation_notification(self, mock_braze_api_clie | |
mock_braze_api_client().create_braze_alias.assert_called_once_with( | ||
[self.pending_enterprise_customer_user.user_email], ENTERPRISE_BRAZE_ALIAS_LABEL) | ||
|
||
@mock.patch('enterprise.tasks.EnterpriseCatalogApiClient', return_value=mock.MagicMock()) | ||
@mock.patch('enterprise.tasks.BrazeAPIClient', return_value=mock.MagicMock()) | ||
def test_fail_send_group_membership_invitation_notification( | ||
self, | ||
mock_braze_api_client, | ||
mock_enterprise_catalog_client, | ||
): | ||
""" | ||
Verify failed send group invitation email | ||
""" | ||
pending_membership = EnterpriseGroupMembershipFactory( | ||
group=self.enterprise_group, | ||
pending_enterprise_customer_user=self.pending_enterprise_customer_user, | ||
enterprise_customer_user=None, | ||
) | ||
admin_email = '[email protected]' | ||
mock_braze_api_client().create_recipients.return_value = { | ||
self.user.email: { | ||
"external_user_id": self.user.id, | ||
"attributes": { | ||
"user_alias": { | ||
"external_id": self.user.id, | ||
"user_alias": self.user.email, | ||
}, | ||
} | ||
} | ||
} | ||
|
||
mock_catalog_content_count = 5 | ||
mock_admin_mailto = f'mailto:{admin_email}' | ||
mock_braze_api_client().generate_mailto_link.return_value = mock_admin_mailto | ||
mock_braze_api_client().create_recipient_no_external_id.return_value = ( | ||
self.pending_enterprise_customer_user.user_email) | ||
mock_enterprise_catalog_client().get_catalog_content_count.return_value = ( | ||
mock_catalog_content_count) | ||
act_by_date = datetime.today() | ||
catalog_uuid = uuid.uuid4() | ||
membership_uuids = EnterpriseGroupMembership.objects.values_list('uuid', flat=True) | ||
mock_braze_api_client().send_campaign_message.side_effect = BrazeClientError( | ||
"Any thing that happens during email") | ||
errored_at = localized_utcnow() | ||
with raises(BrazeClientError): | ||
send_group_membership_invitation_notification( | ||
self.enterprise_customer.uuid, | ||
membership_uuids, | ||
act_by_date, | ||
catalog_uuid) | ||
pending_membership.refresh_from_db() | ||
assert pending_membership.status == 'email_error' | ||
assert pending_membership.errored_at == errored_at | ||
assert pending_membership.recent_action == f"Errored: {errored_at.strftime('%B %d, %Y')}" | ||
|
||
@mock.patch('enterprise.tasks.EnterpriseCatalogApiClient', return_value=mock.MagicMock()) | ||
@mock.patch('enterprise.tasks.BrazeAPIClient', return_value=mock.MagicMock()) | ||
def test_send_group_membership_removal_notification(self, mock_braze_api_client, mock_enterprise_catalog_client): | ||
|
@@ -338,6 +391,56 @@ def test_send_group_membership_removal_notification(self, mock_braze_api_client, | |
[self.pending_enterprise_customer_user.user_email], ENTERPRISE_BRAZE_ALIAS_LABEL) | ||
mock_braze_api_client().send_campaign_message.assert_has_calls(calls) | ||
|
||
@mock.patch('enterprise.tasks.EnterpriseCatalogApiClient', return_value=mock.MagicMock()) | ||
@mock.patch('enterprise.tasks.BrazeAPIClient', return_value=mock.MagicMock()) | ||
def test_fail_send_group_membership_removal_notification( | ||
self, | ||
mock_braze_api_client, | ||
mock_enterprise_catalog_client, | ||
): | ||
""" | ||
Verify failed send group removal email | ||
""" | ||
pending_membership = EnterpriseGroupMembershipFactory( | ||
group=self.enterprise_group, | ||
pending_enterprise_customer_user=self.pending_enterprise_customer_user, | ||
enterprise_customer_user=None, | ||
) | ||
admin_email = '[email protected]' | ||
mock_braze_api_client().create_recipients.return_value = { | ||
self.user.email: { | ||
"external_user_id": self.user.id, | ||
"attributes": { | ||
"user_alias": { | ||
"external_id": self.user.id, | ||
"user_alias": self.user.email, | ||
}, | ||
} | ||
} | ||
} | ||
|
||
mock_catalog_content_count = 5 | ||
mock_admin_mailto = f'mailto:{admin_email}' | ||
mock_braze_api_client().generate_mailto_link.return_value = mock_admin_mailto | ||
mock_braze_api_client().create_recipient_no_external_id.return_value = ( | ||
self.pending_enterprise_customer_user.user_email) | ||
mock_enterprise_catalog_client().get_catalog_content_count.return_value = ( | ||
mock_catalog_content_count) | ||
catalog_uuid = uuid.uuid4() | ||
membership_uuids = EnterpriseGroupMembership.objects.values_list('uuid', flat=True) | ||
mock_braze_api_client().send_campaign_message.side_effect = BrazeClientError( | ||
"Any thing that happens during email") | ||
errored_at = localized_utcnow() | ||
with raises(BrazeClientError): | ||
send_group_membership_removal_notification( | ||
self.enterprise_customer.uuid, | ||
membership_uuids, | ||
catalog_uuid) | ||
pending_membership.refresh_from_db() | ||
assert pending_membership.status == 'email_error' | ||
assert pending_membership.errored_at == localized_utcnow() | ||
assert pending_membership.recent_action == f"Errored: {errored_at.strftime('%B %d, %Y')}" | ||
|
||
@mock.patch('enterprise.tasks.BrazeAPIClient', return_value=mock.MagicMock()) | ||
def test_sso_configuration_oauth_orchestration_email(self, mock_braze_client): | ||
""" | ||
|