diff --git a/BackEnd/profiles/tests/test_email_sending.py b/BackEnd/profiles/tests/test_email_sending.py index f27d27663..c8ceb76fe 100644 --- a/BackEnd/profiles/tests/test_email_sending.py +++ b/BackEnd/profiles/tests/test_email_sending.py @@ -4,6 +4,7 @@ from unittest import mock from django.utils.timezone import now from django.core import mail +from utils.moderation.handle_approved_images import ApprovedImagesDeleter from utils.moderation.send_email import send_moderation_email from utils.moderation.image_moderation import ModerationManager from authentication.factories import UserFactory @@ -23,6 +24,7 @@ def setUp(self): edrpou="99999999", ) + # tests for new images def test_send_moderation_email(self): self.profile.banner = self.banner self.profile.logo = self.logo @@ -114,6 +116,73 @@ def test_send_moderation_email_only_logo(self): os.path.basename(self.logo.image_path.name), ) + def test_send_moderation_email_new_banner_approved_logo(self): + self.profile.banner = self.banner + self.profile.logo = self.logo + self.profile.logo.is_approved = True + + manager = ModerationManager(self.profile) + manager.check_for_moderation() + banner = manager.images["banner"] + logo = manager.images["logo"] + content_is_deleted = manager.content_deleted + send_moderation_email(self.profile, banner, logo, content_is_deleted) + + self.assertEqual(len(mail.outbox), 1) + email_data = mail.outbox[0] + self.assertEqual( + email_data.subject, + f"{self.profile.name} - {self.profile.status_updated_at.strftime('%d.%m.%Y')}: Запит на затвердження змін в обліковому записі компанії", + ) + self.assertIn(self.profile.name, email_data.body) + self.assertIn( + self.profile.status_updated_at.strftime("%d.%m.%Y %H:%M"), + email_data.body, + ) + + self.assertEqual(len(email_data.attachments), 1) + self.assertEqual( + email_data.attachments[0].get_filename(), + os.path.basename(self.banner.image_path.name), + ) + + # test for deleted images + def test_content_deleted_email_with_pending_status(self): + self.profile.status = self.profile.PENDING + manager = ModerationManager(self.profile) + manager.check_for_moderation() + banner = manager.images["banner"] + logo = manager.images["logo"] + content_is_deleted = manager.content_deleted + send_moderation_email(self.profile, banner, logo, content_is_deleted) + + self.assertIn( + "Інформуємо про те що попередньо доданий контент було видалено користувачем.", + mail.outbox[0].body, + ) + self.assertEqual(self.profile.status, self.profile.UNDEFINED) + self.assertIsNone(self.profile.banner) + self.assertIsNone(self.profile.logo) + + def test_remove_pending_image_keep_approved_image(self): + self.profile.banner = self.banner + self.profile.banner.is_approved = True + self.profile.status = self.profile.PENDING + manager = ModerationManager(self.profile) + manager.check_for_moderation() + banner = manager.images["banner"] + logo = manager.images["logo"] + content_is_deleted = manager.content_deleted + send_moderation_email(self.profile, banner, logo, content_is_deleted) + + self.assertIn( + "Інформуємо про те що попередньо доданий контент було видалено користувачем.", + mail.outbox[0].body, + ) + self.assertEqual(self.profile.status, self.profile.APPROVED) + self.assertTrue(self.profile.banner.is_approved) + self.assertIsNone(self.profile.logo) + class TestSendModerationManager(APITestCase): def setUp(self): @@ -139,24 +208,23 @@ def test_needs_moderation_approved_image(self): self.assertFalse(self.manager.needs_moderation(self.logo)) def test_needs_moderation_deleted_image(self): - self.profile.banner = None - self.profile.logo = None self.assertFalse(self.manager.needs_moderation(self.profile.banner)) self.assertFalse(self.manager.needs_moderation(self.profile.logo)) @mock.patch("utils.moderation.image_moderation.now", return_value=now()) def test_update_pending_status(self, mock_now): self.manager.update_pending_status() - self.assertEqual(self.profile.status, "pending") + self.assertEqual(self.profile.status, self.profile.PENDING) self.assertEqual(self.profile.status_updated_at, mock_now.return_value) self.assertTrue(self.manager.moderation_is_needed) + # cases for moderation is needed @mock.patch("utils.moderation.image_moderation.now", return_value=now()) def test_check_for_moderation(self, mock_now): self.profile.banner = self.banner self.profile.logo = self.logo self.manager.check_for_moderation() - self.assertEqual(self.profile.status, "pending") + self.assertEqual(self.profile.status, self.profile.PENDING) self.assertEqual(self.profile.status_updated_at, mock_now.return_value) self.assertTrue(self.manager.moderation_is_needed) self.assertEqual( @@ -165,11 +233,10 @@ def test_check_for_moderation(self, mock_now): ) @mock.patch("utils.moderation.image_moderation.now", return_value=now()) - def test_check_for_moderation_deleted_banner(self, mock_now): - self.profile.banner = None + def test_check_for_moderation_empty_banner(self, mock_now): self.profile.logo = self.logo self.manager.check_for_moderation() - self.assertEqual(self.profile.status, "pending") + self.assertEqual(self.profile.status, self.profile.PENDING) self.assertEqual(self.profile.status_updated_at, mock_now.return_value) self.assertTrue(self.manager.moderation_is_needed) self.assertEqual( @@ -177,21 +244,111 @@ def test_check_for_moderation_deleted_banner(self, mock_now): ) @mock.patch("utils.moderation.image_moderation.now", return_value=now()) - def test_check_for_moderation_deleted_logo(self, mock_now): + def test_check_for_moderation_empty_logo(self, mock_now): self.profile.banner = self.banner - self.profile.logo = None self.manager.check_for_moderation() - self.assertEqual(self.profile.status, "pending") + self.assertEqual(self.profile.status, self.profile.PENDING) self.assertEqual(self.profile.status_updated_at, mock_now.return_value) self.assertTrue(self.manager.moderation_is_needed) self.assertEqual( self.manager.images, {"banner": self.banner, "logo": None} ) - # needs improvement for undefined status - def test_check_for_moderation_deleted_both(self): - self.profile.banner = None - self.profile.logo = None + @mock.patch("utils.moderation.image_moderation.now", return_value=now()) + def test_check_for_moderation_with_approved_image(self, mock_now): + self.profile.banner = self.banner + self.profile.banner.is_approved = True + self.profile.logo = self.logo + self.manager.check_for_moderation() + self.assertEqual(self.profile.status, self.profile.PENDING) + self.assertEqual(self.profile.status_updated_at, mock_now.return_value) + self.assertTrue(self.manager.moderation_is_needed) + self.assertEqual( + self.manager.images, + {"banner": None, "logo": self.logo}, + ) + + # handle the deletion of a new image + @mock.patch("utils.moderation.image_moderation.now", return_value=now()) + def test_handle_approved_image_status_pending(self, mock_now): + self.profile.banner = self.banner + self.profile.banner.is_approved = True + self.profile.status = self.profile.PENDING self.manager.check_for_moderation() + self.assertEqual(self.profile.status, self.profile.APPROVED) + self.assertEqual(self.profile.status_updated_at, mock_now.return_value) self.assertFalse(self.manager.moderation_is_needed) + self.assertTrue(self.manager.content_deleted) + self.assertEqual( + self.manager.images, + {"banner": None, "logo": None}, + ) + + # handle the deletion one of an approved images + def test_handle_approved_image_status_approved(self): + self.profile.banner = self.banner + self.profile.banner.is_approved = True + self.profile.status = self.profile.APPROVED + self.manager.check_for_moderation() + self.assertEqual(self.profile.status, self.profile.APPROVED) + self.assertFalse(self.manager.moderation_is_needed) + self.assertEqual( + self.manager.images, + {"banner": None, "logo": None}, + ) + + def test_handle_undefined_status(self): + self.profile.status = self.profile.PENDING + self.manager.check_for_moderation() + self.assertEqual(self.profile.status, self.profile.UNDEFINED) + self.assertFalse(self.manager.moderation_is_needed) + self.assertTrue(self.manager.content_deleted) + self.assertEqual(self.manager.images, {"banner": None, "logo": None}) + + def test_undefined_status_after_approved_images_deleted(self): + self.profile.status = self.profile.APPROVED + self.manager.check_for_moderation() + self.assertEqual(self.profile.status, self.profile.UNDEFINED) + self.assertFalse(self.manager.moderation_is_needed) + self.assertFalse(self.manager.content_deleted) self.assertEqual(self.manager.images, {"banner": None, "logo": None}) + + +class TestApprovedImagesDeleter(APITestCase): + def setUp(self): + self.banner = ProfileimageFactory(image_type="banner") + self.logo = ProfileimageFactory(image_type="logo") + self.banner_approved = ProfileimageFactory( + image_type="banner", is_approved=True + ) + self.logo_approved = ProfileimageFactory( + image_type="logo", is_approved=True + ) + self.user = UserFactory(email="test1@test.com") + self.profile = ProfileStartupFactory.create( + person=self.user, + official_name="Test Official Startup", + phone="380100102034", + edrpou="99999999", + banner=self.banner, + logo=self.logo, + banner_approved=self.banner_approved, + logo_approved=self.logo_approved, + ) + self.deletion_checker = ApprovedImagesDeleter(self.profile) + + # user removes banner from profile + def test_handle_potential_deletion_banner(self): + self.profile.banner = None + self.profile.banner_approved = self.banner + self.profile.status = self.profile.PENDING + self.deletion_checker.handle_potential_deletion() + self.assertTrue(self.profile.banner_approved.is_deleted) + + # user removes logo from profile + def test_handle_potential_deletion_logo(self): + self.profile.logo = None + self.profile.logo_approved = self.logo + self.profile.status = self.profile.PENDING + self.deletion_checker.handle_potential_deletion() + self.assertTrue(self.profile.logo_approved.is_deleted) diff --git a/BackEnd/profiles/tests/test_reject_moderation_request.py b/BackEnd/profiles/tests/test_reject_moderation_request.py index 6742ac234..5b4ea0839 100644 --- a/BackEnd/profiles/tests/test_reject_moderation_request.py +++ b/BackEnd/profiles/tests/test_reject_moderation_request.py @@ -13,7 +13,6 @@ class TestProfileModeration(APITestCase): def setUp(self) -> None: - self.banner = ProfileimageFactory(image_type="banner") self.logo = ProfileimageFactory(image_type="logo") self.second_banner = ProfileimageFactory(image_type="banner") @@ -29,7 +28,6 @@ def setUp(self) -> None: self.unregistered_user_client = APIClient() def test_reject_banner_and_logo(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -71,7 +69,6 @@ def test_reject_banner_and_logo(self): self.assertFalse(self.user.is_active) def test_reject_banner(self): - # user updates only banner self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -109,7 +106,6 @@ def test_reject_banner(self): self.assertFalse(self.user.is_active) def test_reject_logo(self): - # user updates logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -147,7 +143,6 @@ def test_reject_logo(self): self.assertFalse(self.user.is_active) def test_reject_banner_and_logo_processed_request(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -195,7 +190,6 @@ def test_reject_banner_and_logo_processed_request(self): ) def test_reject_banner_and_logo_outdated_request(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -248,7 +242,6 @@ def test_reject_banner_and_logo_outdated_request(self): self.assertEqual(self.profile.PENDING, self.profile.status) def test_reject_banner_and_logo_wrong_action(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -279,7 +272,6 @@ def test_reject_banner_and_logo_wrong_action(self): ) def test_reject_banner_and_logo_error_in_signed_id(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -308,7 +300,6 @@ def test_reject_banner_and_logo_error_in_signed_id(self): self.assertEqual({"detail": "Not found."}, response.json()) def test_reject_banner_and_logo_non_existing_profile(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -337,7 +328,6 @@ def test_reject_banner_and_logo_non_existing_profile(self): self.assertEqual({"detail": "Not found."}, response.json()) def test_reject_banner_and_logo_empty_image_fields(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -370,7 +360,6 @@ def test_reject_banner_and_logo_empty_image_fields(self): ) def test_login_blocked_user_due_to_rejected_request(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format( @@ -413,7 +402,6 @@ def test_login_blocked_user_due_to_rejected_request(self): ) def test_register_blocked_user_due_to_rejected_request(self): - # user updates both banner and logo self.user_client.patch( path="/api/profiles/{profile_id}".format(